Skip to content

Commit

Permalink
Add elaborates function for comparing specifications
Browse files Browse the repository at this point in the history
  • Loading branch information
HeinrichApfelmus committed Aug 31, 2023
1 parent 724d473 commit eaa1c05
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/fine-types/fine-types.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ library
Language.FineTypes.Typ.Gen
Language.FineTypes.Value
Language.FineTypes.Value.Gen
other-modules:
Language.FineTypes.Elaborate

test-suite unit
import: language, opts-exe
Expand Down
69 changes: 69 additions & 0 deletions lib/fine-types/src/Language/FineTypes/Elaborate.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
module Language.FineTypes.Elaborate
( elaborates
) where

import Prelude

import Language.FineTypes.Typ
( Typ (..), OpTwo (..) )

{-----------------------------------------------------------------------------
Elaboration
------------------------------------------------------------------------------}
-- | Type A elaborates type B if it adds more specific information,
-- such as field or constructor names, while representing the same structure.
--
-- Specifically,
--
-- * Every type elaborates 'Abstract'.
-- * A record type with field names elaborates a product.
-- * A sum type with constructor names elaborates a disjoint sum.
elaborates :: Typ -> Typ -> Bool
elaborates _ Abstract = True
elaborates (Var name1) (Var name2) = name1 == name2
elaborates (Zero c1) (Zero c2) = c1 == c2
elaborates (One op1 a1) (One op2 a2)
= op1 == op2 && elaborates a1 a2
elaborates (Two op1 a1 b1) (Two op2 a2 b2)
= op1 == op2 && elaborates a1 a2 && elaborates b1 b2
elaborates (ProductN fields) a
| Just components <- matchProduct a =
elaboratesSeq (map snd fields) components
| otherwise = False
elaborates (SumN fields) a
| Just summands <- matchSum a =
elaboratesSeq (map snd fields) summands
| otherwise = False
elaborates _ _ = False

-- | Check whether a sequence of types elaborates another sequence.
elaboratesSeq:: [Typ] -> [Typ] -> Bool
elaboratesSeq [] [] = True
elaboratesSeq (x:xs) (y:ys) = elaborates x y && elaboratesSeq xs ys
elaboratesSeq _ _ = False

-- | Match a type @X@ against a product @A1 × A2 × … × An@
-- with at least two components.
--
-- Association does not matter, i.e. @(A × B) × C = A × (B × C)@ have
-- the same components.
matchProduct :: Typ -> Maybe [Typ]
matchProduct typ = case typ of
e@(Two Product2 _ _) -> Just $ match e
_ -> Nothing
where
match (Two Product2 a b) = match a <> match b
match e = [e]

-- | Match a type @X@ against a sum @A1 ⊎ A2 ⊎ … ⊎ An@
-- with at least two summands.
--
-- Association does not matter, i.e. @(A ⊎ B) ⊎ C = A ⊎ (B ⊎ C)@ have
-- the same summands.
matchSum :: Typ -> Maybe [Typ]
matchSum typ = case typ of
e@(Two Sum2 _ _) -> Just $ match e
_ -> Nothing
where
match (Two Sum2 a b) = match a <> match b
match e = [e]

0 comments on commit eaa1c05

Please sign in to comment.