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

Commit 6812e35

Browse files
committed
Terms are free monads.
1 parent 1df04e8 commit 6812e35

File tree

2 files changed

+53
-206
lines changed

2 files changed

+53
-206
lines changed
Lines changed: 16 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,32 @@
1-
{-# LANGUAGE GADTs #-}
1+
{-# LANGUAGE QuantifiedConstraints #-}
22
module Analysis.Syntax
33
( -- * Syntax
44
Term(..)
55
, subterms
6-
-- * Vectors
7-
, Z
8-
, S
9-
, N0
10-
, N1
11-
, N2
12-
, N3
13-
, Vec(..)
146
) where
157

16-
import Data.Foldable (toList)
17-
import Data.Functor.Classes
188
import qualified Data.Set as Set
199

2010
-- Syntax
2111

2212
-- | (Currently) untyped term representations.
23-
data Term sig v where
24-
Var :: v -> Term sig v
25-
(:$:) :: sig n -> Vec n (Term sig v) -> Term sig v
13+
data Term sig v
14+
= Var v
15+
| Term (sig (Term sig v))
2616

27-
instance (Eq1 sig, Eq v) => Eq (Term sig v) where
28-
Var v1 == Var v2 = v1 == v2
29-
a :$: as == b :$: bs = liftEq (\ _ _ -> True) a b && toList as == toList bs
30-
_ == _ = False
17+
instance (forall t . Eq t => Eq (sig t), Eq v) => Eq (Term sig v) where
18+
Var v1 == Var v2 = v1 == v2
19+
Term s1 == Term s2 = s1 == s2
20+
_ == _ = False
3121

32-
instance (Ord1 sig, Ord v) => Ord (Term sig v) where
33-
compare (Var v1) (Var v2) = compare v1 v2
34-
compare (Var _) _ = LT
35-
compare (a :$: as) (b :$: bs) = liftCompare (\ _ _ -> EQ) a b <> compare (toList as) (toList bs)
36-
compare _ _ = GT
22+
instance (forall t . Eq t => Eq (sig t), forall t. Ord t => Ord (sig t), Ord v) => Ord (Term sig v) where
23+
compare (Var v1) (Var v2) = compare v1 v2
24+
compare (Var _) _ = LT
25+
compare (Term s1) (Term s2) = compare s1 s2
26+
compare _ _ = GT
3727

3828

39-
subterms :: (Ord1 sig, Ord v) => Term sig v -> Set.Set (Term sig v)
29+
subterms :: (forall t . Eq t => Eq (sig t), forall t . Ord t => Ord (sig t), Ord v, Foldable sig) => Term sig v -> Set.Set (Term sig v)
4030
subterms t = case t of
41-
Var _ -> Set.singleton t
42-
_ :$: ts -> Set.insert t (foldMap subterms ts)
43-
44-
45-
-- Vectors
46-
47-
data Z
48-
data S n
49-
50-
type N0 = Z
51-
type N1 = S N0
52-
type N2 = S N1
53-
type N3 = S N2
54-
55-
56-
-- FIXME: move this into its own module, or use a dependency, or something.
57-
data Vec n a where
58-
Nil :: Vec Z a
59-
Cons :: a -> Vec n a -> Vec (S n) a
60-
61-
instance Eq a => Eq (Vec n a) where
62-
Nil == Nil = True
63-
Cons a as == Cons b bs = a == b && as == bs
64-
65-
instance Ord a => Ord (Vec n a) where
66-
compare Nil Nil = EQ
67-
compare (Cons a as) (Cons b bs) = a `compare` b <> as `compare` bs
68-
69-
instance Foldable (Vec n) where
70-
foldMap _ Nil = mempty
71-
foldMap f (Cons a as) = f a <> foldMap f as
31+
Var _ -> Set.singleton t
32+
Term s -> Set.insert t (foldMap subterms s)
Lines changed: 37 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,11 @@
1+
{-# LANGUAGE DeriveTraversable #-}
12
{-# LANGUAGE FlexibleContexts #-}
2-
{-# LANGUAGE GADTs #-}
33
{-# LANGUAGE LambdaCase #-}
4-
{-# LANGUAGE PatternSynonyms #-}
5-
{-# LANGUAGE ViewPatterns #-}
64
-- | This belongs in @semantic-python@ instead of @semantic-analysis@, but for the sake of expedience…
75
module Analysis.Syntax.Python
86
( -- * Syntax
97
Term
108
, Python(..)
11-
, pattern Noop
12-
, pattern Iff
13-
, pattern Bool
14-
, pattern String
15-
, pattern Throw
16-
, pattern Let
17-
, pattern (:>>)
18-
, pattern Import
19-
, pattern Function
20-
, pattern Call
21-
, pattern Locate
229
-- * Abstract interpretation
2310
, eval0
2411
, eval
@@ -33,7 +20,6 @@ import Analysis.VM
3320
import Control.Effect.Labelled
3421
import Control.Effect.Reader
3522
import Data.Function (fix)
36-
import Data.Functor.Classes (Eq1 (..), Ord1 (..))
3723
import Data.List.NonEmpty (NonEmpty)
3824
import Data.Text (Text)
3925
import Source.Span (Span)
@@ -42,123 +28,22 @@ import Source.Span (Span)
4228

4329
type Term = T.Term Python Name
4430

45-
data Python arity where
46-
Noop' :: Python T.N0
47-
Iff' :: Python T.N3
48-
Bool' :: Bool -> Python T.N0
49-
String' :: Text -> Python T.N0
50-
Throw' :: Python T.N1
51-
Let' :: Name -> Python T.N2
52-
(:>>>) :: Python T.N2
53-
Import' :: NonEmpty Text -> Python T.N0
54-
Function' :: Name -> [Name] -> Python T.N1
55-
Call' :: Python T.N2 -- ^ Second should be an @ANil'@ or @ACons'@.
56-
ANil' :: Python T.N0
57-
ACons' :: Python T.N2 -- ^ Second should be an @ANil'@ or @ACons'@.
58-
Locate' :: Span -> Python T.N1
59-
60-
infixl 1 :>>>
61-
62-
pattern Noop :: T.Term Python v
63-
pattern Noop = Noop' T.:$: T.Nil
64-
65-
pattern Iff :: T.Term Python v -> T.Term Python v -> T.Term Python v -> T.Term Python v
66-
pattern Iff c t e = Iff' T.:$: T.Cons c (T.Cons t (T.Cons e T.Nil))
67-
68-
pattern Bool :: Bool -> T.Term Python v
69-
pattern Bool b = Bool' b T.:$: T.Nil
70-
71-
pattern String :: Text -> T.Term Python v
72-
pattern String t = String' t T.:$: T.Nil
73-
74-
pattern Throw :: T.Term Python v -> T.Term Python v
75-
pattern Throw e = Throw' T.:$: T.Cons e T.Nil
76-
77-
pattern Let :: Name -> T.Term Python v -> T.Term Python v -> T.Term Python v
78-
pattern Let n v b = Let' n T.:$: T.Cons v (T.Cons b T.Nil)
79-
80-
pattern (:>>) :: T.Term Python v -> T.Term Python v -> T.Term Python v
81-
pattern s :>> t = (:>>>) T.:$: T.Cons s (T.Cons t T.Nil)
31+
data Python t
32+
= Noop
33+
| Iff t t t
34+
| Bool Bool
35+
| String Text
36+
| Throw t
37+
| Let Name t t
38+
| t :>> t
39+
| Import (NonEmpty Text)
40+
| Function Name [Name] t
41+
| Call t [t]
42+
| Locate Span t
43+
deriving (Eq, Foldable, Functor, Ord, Show, Traversable)
8244

8345
infixl 1 :>>
8446

85-
pattern Import :: NonEmpty Text -> T.Term Python v
86-
pattern Import i = Import' i T.:$: T.Nil
87-
88-
pattern Function :: Name -> [Name] -> T.Term Python v -> T.Term Python v
89-
pattern Function n as b = Function' n as T.:$: T.Cons b T.Nil
90-
91-
pattern Call
92-
:: T.Term Python v
93-
-> [T.Term Python v]
94-
-> T.Term Python v
95-
pattern Call f as <- Call' T.:$: T.Cons f (T.Cons (fromArgs -> as) T.Nil)
96-
where Call f as = Call' T.:$: T.Cons f (T.Cons (foldr ACons ANil as) T.Nil)
97-
98-
fromArgs :: T.Term Python v -> [T.Term Python v]
99-
fromArgs = \case
100-
ANil -> []
101-
ACons a as -> a:fromArgs as
102-
_ -> fail "unexpected constructor in spine of argument list"
103-
104-
pattern ANil :: T.Term Python v
105-
pattern ANil = ANil' T.:$: T.Nil
106-
107-
pattern ACons :: T.Term Python v -> T.Term Python v -> T.Term Python v
108-
pattern ACons a as = ACons' T.:$: T.Cons a (T.Cons as T.Nil)
109-
110-
pattern Locate :: Span -> T.Term Python v -> T.Term Python v
111-
pattern Locate s t = Locate' s T.:$: T.Cons t T.Nil
112-
113-
{-# COMPLETE Noop, Iff, Bool, String, Throw, Let, (:>>), Import, Function, Call, Locate #-}
114-
115-
116-
instance Eq1 Python where
117-
liftEq _ a b = case (a, b) of
118-
(Noop', Noop') -> True
119-
(Iff', Iff') -> True
120-
(Bool' b1, Bool' b2) -> b1 == b2
121-
(String' s1, String' s2) -> s1 == s2
122-
(Throw', Throw') -> True
123-
(Let' n1, Let' n2) -> n1 == n2
124-
((:>>>), (:>>>)) -> True
125-
(Import' i1, Import' i2) -> i1 == i2
126-
(Function' n1 as1, Function' n2 as2) -> n1 == n2 && as1 == as2
127-
(Call', Call') -> True
128-
(ANil', ANil') -> True
129-
(ACons', ACons') -> True
130-
(Locate' s1, Locate' s2) -> s1 == s2
131-
_ -> False
132-
133-
instance Ord1 Python where
134-
liftCompare _ a b = case (a, b) of
135-
(Noop', Noop') -> EQ
136-
(Noop', _) -> LT
137-
(Iff', Iff') -> EQ
138-
(Iff', _) -> LT
139-
(Bool' b1, Bool' b2) -> compare b1 b2
140-
(Bool' _, _) -> LT
141-
(String' s1, String' s2) -> compare s1 s2
142-
(String' _, _) -> LT
143-
(Throw', Throw') -> EQ
144-
(Throw', _) -> LT
145-
(Let' n1, Let' n2) -> compare n1 n2
146-
(Let' _, _) -> LT
147-
((:>>>), (:>>>)) -> EQ
148-
((:>>>), _) -> LT
149-
(Import' i1, Import' i2) -> compare i1 i2
150-
(Import' _, _) -> LT
151-
(Function' n1 as1, Function' n2 as2) -> compare n1 n2 <> compare as1 as2
152-
(Function' _ _, _) -> LT
153-
(Call', Call') -> EQ
154-
(Call', _) -> LT
155-
(ANil', ANil') -> EQ
156-
(ANil', _) -> LT
157-
(ACons', ACons') -> EQ
158-
(ACons', _) -> LT
159-
(Locate' s1, Locate' s2) -> compare s1 s2
160-
(Locate' _, _) -> LT
161-
16247

16348
-- Abstract interpretation
16449

@@ -170,27 +55,28 @@ eval
17055
=> (Term -> m val)
17156
-> (Term -> m val)
17257
eval eval = \case
173-
T.Var n -> lookupEnv n >>= maybe (dvar n) fetch
174-
Noop -> dunit
175-
Iff c t e -> do
176-
c' <- eval c
177-
dif c' (eval t) (eval e)
178-
Bool b -> dbool b
179-
String s -> dstring s
180-
Throw e -> eval e >>= ddie
181-
Let n v b -> do
182-
v' <- eval v
183-
let' n v' (eval b)
184-
t :>> u -> do
185-
t' <- eval t
186-
u' <- eval u
187-
t' >>> u'
188-
Import ns -> S.simport ns >> dunit
189-
Function n ps b -> letrec n (dabs ps (foldr (\ (p, a) m -> let' p a m) (eval b) . zip ps))
190-
Call f as -> do
191-
f' <- eval f
192-
as' <- traverse eval as
193-
dapp f' as'
194-
Locate s t -> local (setSpan s) (eval t)
58+
T.Var n -> lookupEnv n >>= maybe (dvar n) fetch
59+
T.Term s -> case s of
60+
Noop -> dunit
61+
Iff c t e -> do
62+
c' <- eval c
63+
dif c' (eval t) (eval e)
64+
Bool b -> dbool b
65+
String s -> dstring s
66+
Throw e -> eval e >>= ddie
67+
Let n v b -> do
68+
v' <- eval v
69+
let' n v' (eval b)
70+
t :>> u -> do
71+
t' <- eval t
72+
u' <- eval u
73+
t' >>> u'
74+
Import ns -> S.simport ns >> dunit
75+
Function n ps b -> letrec n (dabs ps (foldr (\ (p, a) m -> let' p a m) (eval b) . zip ps))
76+
Call f as -> do
77+
f' <- eval f
78+
as' <- traverse eval as
79+
dapp f' as'
80+
Locate s t -> local (setSpan s) (eval t)
19581
where
19682
setSpan s r = r{ refSpan = s }

0 commit comments

Comments
 (0)