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

Commit a9894d0

Browse files
committed
Bind polytypes as scope-safe syntax.
1 parent 05a3097 commit a9894d0

1 file changed

Lines changed: 31 additions & 43 deletions

File tree

semantic-core/src/Analysis/Typecheck.hs

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
1-
{-# LANGUAGE DeriveFunctor, FlexibleContexts, FlexibleInstances, LambdaCase, OverloadedStrings, RecordWildCards, ScopedTypeVariables, TypeApplications #-}
1+
{-# LANGUAGE DeriveGeneric, DeriveTraversable, FlexibleContexts, FlexibleInstances, LambdaCase, OverloadedStrings, RecordWildCards, ScopedTypeVariables, TypeApplications #-}
22
module Analysis.Typecheck
33
( Monotype (..)
44
, Meta
55
, Polytype (PForAll, PBool, PFree, PArr)
66
, Scope
7-
, Analysis.Typecheck.bind
8-
, Analysis.Typecheck.instantiate
97
, typecheckingFlowInsensitive
108
, typecheckingAnalysis
119
) where
1210

1311
import Analysis.Eval
1412
import Analysis.FlowInsensitive
1513
import Control.Applicative (Alternative (..))
16-
import Control.Effect
14+
import Control.Effect.Carrier
1715
import Control.Effect.Fail
1816
import Control.Effect.Fresh as Fresh
1917
import Control.Effect.Reader hiding (Local)
2018
import Control.Effect.State
2119
import Control.Monad (unless)
20+
import Control.Monad.Module
2221
import qualified Data.Core as Core
2322
import Data.File
2423
import Data.Foldable (foldl', for_)
@@ -30,9 +29,11 @@ import Data.List.NonEmpty (nonEmpty)
3029
import Data.Loc
3130
import qualified Data.Map as Map
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 GHC.Generics (Generic1)
3637
import Prelude hiding (fail)
3738

3839
data Monotype a
@@ -47,31 +48,40 @@ data Monotype a
4748

4849
type Meta = Int
4950

50-
data Polytype
51-
= PForAll Scope
51+
data Polytype f a
52+
= PForAll (Scope () f a)
5253
| PUnit
5354
| PBool
5455
| PString
5556
| PBound Int
5657
| 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-
64-
forAll :: Gensym -> Polytype -> Polytype
65-
forAll n body = PForAll (Analysis.Typecheck.bind n body)
66-
67-
forAlls :: Foldable t => t Gensym -> Polytype -> Polytype
58+
| PArr (f a) (f a)
59+
| PRecord (Map.Map User (f a))
60+
deriving (Foldable, Functor, Generic1, Traversable)
61+
62+
instance HFunctor Polytype
63+
instance RightModule Polytype where
64+
PForAll b >>=* f = PForAll (b >>=* f)
65+
PUnit >>=* _ = PUnit
66+
PBool >>=* _ = PBool
67+
PString >>=* _ = PString
68+
PBound i >>=* _ = PBound i
69+
PFree n >>=* _ = PFree n
70+
PArr a b >>=* f = PArr (a >>= f) (b >>= f)
71+
PRecord m >>=* f = PRecord ((>>= f) <$> m)
72+
73+
74+
forAll :: (Eq a, Carrier sig m, Member Polytype sig) => a -> m a -> m a
75+
forAll n body = send (PForAll (Data.Scope.bind1 n body))
76+
77+
forAlls :: (Eq a, Carrier sig m, Member Polytype sig, Foldable t) => t a -> m a -> m a
6878
forAlls ns body = foldr forAll body ns
6979

70-
generalize :: (Carrier sig m, Member Naming sig) => Monotype Meta -> m Polytype
80+
generalize :: (Carrier sig m, Member Naming sig) => Monotype Meta -> m (Term Polytype Gensym)
7181
generalize ty = namespace "generalize" $ do
7282
Gensym root _ <- Name.fresh
7383
pure (forAlls (map (Gensym root) (IntSet.toList (mvs ty))) (fold root ty))
74-
where fold root = \case
84+
where fold root = Term . \case
7585
MUnit -> PUnit
7686
MBool -> PBool
7787
MString -> PString
@@ -80,30 +90,8 @@ generalize ty = namespace "generalize" $ do
8090
MArr a b -> PArr (fold root a) (fold root b)
8191
MRecord fs -> PRecord (fold root <$> fs)
8292

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)
86-
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
90-
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)
104-
105-
106-
typecheckingFlowInsensitive :: [File (Term Core.Core Name)] -> (Heap Name (Monotype Meta), [File (Either (Loc, String) Polytype)])
93+
94+
typecheckingFlowInsensitive :: [File (Term Core.Core Name)] -> (Heap Name (Monotype Meta), [File (Either (Loc, String) (Term Polytype Gensym))])
10795
typecheckingFlowInsensitive
10896
= run
10997
. runFresh

0 commit comments

Comments
 (0)