Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 9199555

Browse files
authored
Merge pull request #201 from github/types-as-syntax
Types as syntax
2 parents 5179e88 + 611294b commit 9199555

File tree

3 files changed

+86
-137
lines changed

3 files changed

+86
-137
lines changed
Lines changed: 73 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,110 @@
1-
{-# LANGUAGE DeriveFunctor, FlexibleContexts, FlexibleInstances, LambdaCase, OverloadedStrings, RecordWildCards, ScopedTypeVariables, TypeApplications #-}
1+
{-# LANGUAGE DeriveGeneric, DeriveTraversable, FlexibleContexts, FlexibleInstances, LambdaCase, OverloadedStrings, QuantifiedConstraints, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeOperators #-}
22
module Analysis.Typecheck
33
( Monotype (..)
44
, Meta
5-
, Polytype (PForAll, PBool, PFree, PArr)
6-
, Scope
7-
, Analysis.Typecheck.bind
8-
, Analysis.Typecheck.instantiate
5+
, Polytype (..)
96
, typecheckingFlowInsensitive
107
, typecheckingAnalysis
118
) where
129

1310
import Analysis.Eval
1411
import Analysis.FlowInsensitive
1512
import Control.Applicative (Alternative (..))
16-
import Control.Effect
13+
import Control.Effect.Carrier
1714
import Control.Effect.Fail
1815
import Control.Effect.Fresh as Fresh
1916
import Control.Effect.Reader hiding (Local)
2017
import Control.Effect.State
2118
import Control.Monad (unless)
19+
import Control.Monad.Module
2220
import qualified Data.Core as Core
2321
import Data.File
24-
import Data.Foldable (foldl', for_)
22+
import Data.Foldable (for_)
2523
import Data.Function (fix)
2624
import Data.Functor (($>))
2725
import qualified Data.IntMap as IntMap
2826
import qualified Data.IntSet as IntSet
2927
import Data.List.NonEmpty (nonEmpty)
3028
import Data.Loc
3129
import qualified Data.Map as Map
30+
import Data.Maybe (fromJust, fromMaybe)
3231
import Data.Name as Name
32+
import Data.Scope
3333
import qualified Data.Set as Set
3434
import Data.Stack
3535
import Data.Term
36+
import Data.Void
37+
import GHC.Generics (Generic1)
3638
import Prelude hiding (fail)
3739

38-
data Monotype a
39-
= MBool
40-
| MUnit
41-
| MString
42-
| MMeta a
43-
| MFree Gensym
44-
| MArr (Monotype a) (Monotype a)
45-
| MRecord (Map.Map User (Monotype a))
46-
deriving (Eq, Functor, Ord, Show)
40+
data Monotype f a
41+
= Bool
42+
| Unit
43+
| String
44+
| Arr (f a) (f a)
45+
| Record (Map.Map User (f a))
46+
deriving (Foldable, Functor, Generic1, Traversable)
47+
48+
deriving instance (Eq a, forall a . Eq a => Eq (f a), Monad f) => Eq (Monotype f a)
49+
deriving instance (Ord a, forall a . Eq a => Eq (f a)
50+
, forall a . Ord a => Ord (f a), Monad f) => Ord (Monotype f a)
51+
deriving instance (Show a, forall a . Show a => Show (f a)) => Show (Monotype f a)
52+
53+
instance HFunctor Monotype
54+
instance RightModule Monotype where
55+
Unit >>=* _ = Unit
56+
Bool >>=* _ = Bool
57+
String >>=* _ = String
58+
Arr a b >>=* f = Arr (a >>= f) (b >>= f)
59+
Record m >>=* f = Record ((>>= f) <$> m)
4760

4861
type Meta = Int
4962

50-
data Polytype
51-
= PForAll Scope
52-
| PUnit
53-
| PBool
54-
| PString
55-
| PBound Int
56-
| PFree Gensym
57-
| PArr Polytype Polytype
58-
| PRecord (Map.Map User Polytype)
59-
deriving (Eq, Ord, Show)
60-
61-
newtype Scope = Scope Polytype
62-
deriving (Eq, Ord, Show)
63+
newtype Polytype f a = PForAll (Scope () f a)
64+
deriving (Foldable, Functor, Generic1, Traversable)
6365

64-
forAll :: Gensym -> Polytype -> Polytype
65-
forAll n body = PForAll (Analysis.Typecheck.bind n body)
66+
deriving instance (Eq a, forall a . Eq a => Eq (f a), Monad f) => Eq (Polytype f a)
67+
deriving instance (Ord a, forall a . Eq a => Eq (f a)
68+
, forall a . Ord a => Ord (f a), Monad f) => Ord (Polytype f a)
69+
deriving instance (Show a, forall a . Show a => Show (f a)) => Show (Polytype f a)
6670

67-
forAlls :: Foldable t => t Gensym -> Polytype -> Polytype
68-
forAlls ns body = foldr forAll body ns
71+
instance HFunctor Polytype
72+
instance RightModule Polytype where
73+
PForAll b >>=* f = PForAll (b >>=* f)
6974

70-
generalize :: (Carrier sig m, Member Naming sig) => Monotype Meta -> m Polytype
71-
generalize ty = namespace "generalize" $ do
72-
Gensym root _ <- Name.fresh
73-
pure (forAlls (map (Gensym root) (IntSet.toList (mvs ty))) (fold root ty))
74-
where fold root = \case
75-
MUnit -> PUnit
76-
MBool -> PBool
77-
MString -> PString
78-
MMeta i -> PFree (Gensym root i)
79-
MFree n -> PFree n
80-
MArr a b -> PArr (fold root a) (fold root b)
81-
MRecord fs -> PRecord (fold root <$> fs)
8275

83-
-- | Bind occurrences of a 'Gensym' in a 'Polytype' term, producing a 'Scope' in which the 'Gensym' is bound.
84-
bind :: Gensym -> Polytype -> Scope
85-
bind name = Scope . substIn (\ i n -> if name == n then PBound i else PFree n) (const PBound)
76+
forAll :: (Eq a, Carrier sig m, Member Polytype sig) => a -> m a -> m a
77+
forAll n body = send (PForAll (Data.Scope.bind1 n body))
8678

87-
-- | Substitute a 'Polytype' term for the free variable in a given 'Scope', producing a closed 'Polytype' term.
88-
instantiate :: Polytype -> Scope -> Polytype
89-
instantiate image (Scope body) = substIn (const PFree) (\ i j -> if i == j then image else PBound j) body
79+
forAlls :: (Eq a, Carrier sig m, Member Polytype sig, Foldable t) => t a -> m a -> m a
80+
forAlls ns body = foldr forAll body ns
9081

91-
substIn :: (Int -> Gensym -> Polytype)
92-
-> (Int -> Int -> Polytype)
93-
-> Polytype
94-
-> Polytype
95-
substIn free bound = go 0
96-
where go i (PFree name) = free i name
97-
go i (PBound j) = bound i j
98-
go i (PForAll (Scope body)) = PForAll (Scope (go (succ i) body))
99-
go _ PUnit = PUnit
100-
go _ PBool = PBool
101-
go _ PString = PString
102-
go i (PArr a b) = PArr (go i a) (go i b)
103-
go i (PRecord fs) = PRecord (go i <$> fs)
82+
generalize :: Term Monotype Meta -> Term (Polytype :+: Monotype) Void
83+
generalize ty = fromJust (closed (forAlls (IntSet.toList (mvs ty)) (hoistTerm R ty)))
10484

10585

106-
typecheckingFlowInsensitive :: [File (Term Core.Core Name)] -> (Heap Name (Monotype Meta), [File (Either (Loc, String) Polytype)])
86+
typecheckingFlowInsensitive :: [File (Term Core.Core Name)] -> (Heap Name (Term Monotype Meta), [File (Either (Loc, String) (Term (Polytype :+: Monotype) Void))])
10787
typecheckingFlowInsensitive
10888
= run
10989
. runFresh
11090
. runNaming
11191
. runHeap (Gen (Gensym (Nil :> "root") 0))
112-
. (>>= traverse (traverse (traverse generalize)))
92+
. fmap (fmap (fmap (fmap generalize)))
11393
. traverse runFile
11494

11595
runFile :: ( Carrier sig m
11696
, Effect sig
11797
, Member Fresh sig
11898
, Member Naming sig
119-
, Member (State (Heap Name (Monotype Meta))) sig
99+
, Member (State (Heap Name (Term Monotype Meta))) sig
120100
)
121101
=> File (Term Core.Core Name)
122-
-> m (File (Either (Loc, String) (Monotype Meta)))
102+
-> m (File (Either (Loc, String) (Term Monotype Meta)))
123103
runFile file = traverse run file
124104
where run
125105
= (\ m -> do
126106
(subst, t) <- m
127-
modify @(Heap Name (Monotype Meta)) (substAll subst)
107+
modify @(Heap Name (Term Monotype Meta)) (fmap (Set.map (substAll subst)))
128108
pure (substAll subst <$> t))
129109
. runState (mempty :: Substitution)
130110
. runReader (fileLoc file)
@@ -139,7 +119,7 @@ runFile file = traverse run file
139119
v <$ for_ bs (unify v))
140120
. convergeTerm (fix (cacheTerm . eval typecheckingAnalysis))
141121

142-
typecheckingAnalysis :: (Alternative m, Carrier sig m, Member Fresh sig, Member (State (Set.Set Constraint)) sig, Member (State (Heap Name (Monotype Meta))) sig, MonadFail m) => Analysis Name (Monotype Meta) m
122+
typecheckingAnalysis :: (Alternative m, Carrier sig m, Member Fresh sig, Member (State (Set.Set Constraint)) sig, Member (State (Heap Name (Term Monotype Meta))) sig, MonadFail m) => Analysis Name (Term Monotype Meta) m
143123
typecheckingAnalysis = Analysis{..}
144124
where alloc = pure
145125
bind _ _ = pure ()
@@ -152,108 +132,65 @@ typecheckingAnalysis = Analysis{..}
152132
arg <- meta
153133
assign addr arg
154134
ty <- eval body
155-
pure (MArr arg ty)
135+
pure (Term (Arr arg ty))
156136
apply _ f a = do
157137
_A <- meta
158138
_B <- meta
159-
unify (MArr _A _B) f
139+
unify (Term (Arr _A _B)) f
160140
unify _A a
161141
pure _B
162-
unit = pure MUnit
163-
bool _ = pure MBool
164-
asBool b = unify MBool b >> pure True <|> pure False
165-
string _ = pure MString
166-
asString s = unify MString s $> mempty
142+
unit = pure (Term Unit)
143+
bool _ = pure (Term Bool)
144+
asBool b = unify (Term Bool) b >> pure True <|> pure False
145+
string _ = pure (Term String)
146+
asString s = unify (Term String) s $> mempty
167147
frame = fail "unimplemented"
168148
edge _ _ = pure ()
169149
_ ... m = m
170150

171151

172-
data Constraint = Monotype Meta :===: Monotype Meta
152+
data Constraint = Term Monotype Meta :===: Term Monotype Meta
173153
deriving (Eq, Ord, Show)
174154

175155
infix 4 :===:
176156

177157
data Solution
178-
= Int := Monotype Meta
158+
= Int := Term Monotype Meta
179159
deriving (Eq, Ord, Show)
180160

181161
infix 5 :=
182162

183-
meta :: (Carrier sig m, Member Fresh sig) => m (Monotype Meta)
184-
meta = MMeta <$> Fresh.fresh
163+
meta :: (Carrier sig m, Member Fresh sig) => m (Term Monotype Meta)
164+
meta = pure <$> Fresh.fresh
185165

186-
unify :: (Carrier sig m, Member (State (Set.Set Constraint)) sig) => Monotype Meta -> Monotype Meta -> m ()
166+
unify :: (Carrier sig m, Member (State (Set.Set Constraint)) sig) => Term Monotype Meta -> Term Monotype Meta -> m ()
187167
unify t1 t2
188168
| t1 == t2 = pure ()
189169
| otherwise = modify (<> Set.singleton (t1 :===: t2))
190170

191-
type Substitution = IntMap.IntMap (Monotype Meta)
171+
type Substitution = IntMap.IntMap (Term Monotype Meta)
192172

193173
solve :: (Carrier sig m, Member (State Substitution) sig, MonadFail m) => Set.Set Constraint -> m ()
194174
solve cs = for_ cs solve
195175
where solve = \case
196176
-- FIXME: how do we enforce proper subtyping? row polymorphism or something?
197-
MRecord f1 :===: MRecord f2 -> traverse solve (Map.intersectionWith (:===:) f1 f2) $> ()
198-
MArr a1 b1 :===: MArr a2 b2 -> solve (a1 :===: a2) *> solve (b1 :===: b2)
199-
MMeta m1 :===: MMeta m2 | m1 == m2 -> pure ()
200-
MMeta m1 :===: t2 -> do
177+
Term (Record f1) :===: Term (Record f2) -> traverse solve (Map.intersectionWith (:===:) f1 f2) $> ()
178+
Term (Arr a1 b1) :===: Term (Arr a2 b2) -> solve (a1 :===: a2) *> solve (b1 :===: b2)
179+
Var m1 :===: Var m2 | m1 == m2 -> pure ()
180+
Var m1 :===: t2 -> do
201181
sol <- solution m1
202182
case sol of
203183
Just (_ := t1) -> solve (t1 :===: t2)
204184
Nothing | m1 `IntSet.member` mvs t2 -> fail ("Occurs check failure: " <> show m1 <> " :===: " <> show t2)
205-
| otherwise -> modify (IntMap.insert m1 t2 . subst (m1 := t2))
206-
t1 :===: MMeta m2 -> solve (MMeta m2 :===: t1)
185+
| otherwise -> modify (IntMap.insert m1 t2 . fmap (substAll (IntMap.singleton m1 t2)))
186+
t1 :===: Var m2 -> solve (Var m2 :===: t1)
207187
t1 :===: t2 -> unless (t1 == t2) $ fail ("Type mismatch:\nexpected: " <> show t1 <> "\n actual: " <> show t2)
208188

209189
solution m = fmap (m :=) <$> gets (IntMap.lookup m)
210190

211-
substAll :: Substitutable t => Substitution -> t -> t
212-
substAll s a = foldl' (flip subst) a (map (uncurry (:=)) (IntMap.toList s))
213-
214-
215-
class FreeVariables t where
216-
mvs :: t -> IntSet.IntSet
217-
218-
instance FreeVariables (Monotype Meta) where
219-
mvs MUnit = mempty
220-
mvs MBool = mempty
221-
mvs MString = mempty
222-
mvs (MArr a b) = mvs a <> mvs b
223-
mvs (MMeta m) = IntSet.singleton m
224-
mvs (MFree _) = mempty
225-
mvs (MRecord fs) = foldMap mvs fs
226-
227-
instance FreeVariables Constraint where
228-
mvs (t1 :===: t2) = mvs t1 <> mvs t2
229-
230-
class Substitutable t where
231-
subst :: Solution -> t -> t
232-
233-
instance Substitutable (Monotype Meta) where
234-
subst s con = case con of
235-
MUnit -> MUnit
236-
MBool -> MBool
237-
MString -> MString
238-
MArr a b -> MArr (subst s a) (subst s b)
239-
MMeta m'
240-
| m := t <- s
241-
, m == m' -> t
242-
| otherwise -> MMeta m'
243-
MFree n -> MFree n
244-
MRecord fs -> MRecord (subst s <$> fs)
245-
246-
instance Substitutable Constraint where
247-
subst s (t1 :===: t2) = subst s t1 :===: subst s t2
248-
249-
instance Substitutable Solution where
250-
subst s (m := t) = m := subst s t
251-
252-
instance Substitutable a => Substitutable (IntMap.IntMap a) where
253-
subst s = IntMap.map (subst s)
254191

255-
instance (Ord a, Substitutable a) => Substitutable (Set.Set a) where
256-
subst s = Set.map (subst s)
192+
mvs :: Foldable t => t Meta -> IntSet.IntSet
193+
mvs = foldMap IntSet.singleton
257194

258-
instance Substitutable v => Substitutable (Map.Map k v) where
259-
subst s = fmap (subst s)
195+
substAll :: Monad t => IntMap.IntMap (t Meta) -> t Meta -> t Meta
196+
substAll s a = a >>= \ i -> fromMaybe (pure i) (IntMap.lookup i s)

semantic-core/src/Data/Scope.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
module Data.Scope
33
( Incr(..)
44
, incr
5+
, closed
56
, Scope(..)
67
, fromScope
78
, toScope
@@ -44,6 +45,10 @@ incr :: (a -> c) -> (b -> c) -> Incr a b -> c
4445
incr z s = \case { Z a -> z a ; S b -> s b }
4546

4647

48+
closed :: Traversable f => f a -> Maybe (f b)
49+
closed = traverse (const Nothing)
50+
51+
4752
newtype Scope a f b = Scope { unScope :: f (Incr a (f b)) }
4853
deriving (Foldable, Functor, Traversable)
4954

semantic-core/src/Data/Term.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
{-# LANGUAGE DeriveTraversable, FlexibleInstances, MultiParamTypeClasses, QuantifiedConstraints, StandaloneDeriving, UndecidableInstances #-}
1+
{-# LANGUAGE DeriveTraversable, FlexibleInstances, MultiParamTypeClasses, QuantifiedConstraints, RankNTypes, StandaloneDeriving, UndecidableInstances #-}
22
module Data.Term
33
( Term(..)
4+
, hoistTerm
45
) where
56

67
import Control.Effect.Carrier
@@ -41,3 +42,9 @@ instance RightModule sig => Monad (Term sig) where
4142

4243
instance RightModule sig => Carrier sig (Term sig) where
4344
eff = Term
45+
46+
47+
hoistTerm :: (HFunctor sig, forall g . Functor g => Functor (sig g)) => (forall m x . sig m x -> sig' m x) -> Term sig a -> Term sig' a
48+
hoistTerm f = go
49+
where go (Var v) = Var v
50+
go (Term t) = Term (f (hmap (hoistTerm f) t))

0 commit comments

Comments
 (0)