-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMain.hs
106 lines (86 loc) · 2.41 KB
/
Main.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import Control.Applicative ((<|>))
import Control.Monad.State
import AST
import Descent
-- Test subject.
--
ast :: Prog
ast
= Let (Bind "id" $ Lam "a" "a")
$ Let (Bind "const" $ Lam "a" $ Lam "b" "a")
$ Match (App "id" (Const $ I 1))
[ Alt (IsVar "a" `As` IsVar "b")
(App "const" (App (App "plus" "a") "b"))
]
-- Our working state. Is a list of stack frames.
--
type Scope = [[String]]
-- Our working monad.
--
-- The state consists of stack frames of names.
--
type ScopeM = StateT Scope IO
-- Run the `ScopeM`.
--
runScopeM :: ScopeM r -> IO r
runScopeM
= flip evalStateT []
-- Find the current depth of the name and attach it.
rename :: Name -> ScopeM Name
rename name = do
scope <- get
case find (unName name) scope of
Just index -> return $ addIndex name index
Nothing -> return name
-- Find the current depth of the name.
find :: String -> Scope -> Maybe Int
find _ [] = Nothing
find n (frame : rest) = case find' n frame of
Nothing -> (length frame +) <$> find n rest
Just n -> return n
where
find' n (n' : rest')
| n == n' = return 0
| otherwise = (1 +) <$> find' n rest'
find' _ [] = Nothing
-- Add index to the name.
--
addIndex :: Name -> Int -> Name
addIndex (Name name _) index = Name name index
-- Preparations before entering a `Prog`-ram.
--
-- If the name ("a") is bound, convert it to "a'N", where N is its depth in stack.
--
useName :: Transform ScopeM
useName = pack
[ Entering `with_` \case
Lam (NameDecl n) _ -> modify ([unName n] :)
_ -> return ()
, Entering `with_` \case
Alt {} -> modify ([] :)
, Entering `with_` \case
IsVar (NameDecl n) -> modify \(top : s) -> (unName n : top) : s
_ -> return ()
, coercing @NameVar Inside rename
, coercing @NameDecl Inside rename
-- Small hack. We assign depth the name would take (but it didn't).
, Inside `with` \(NameLet name) -> do
return $ NameLet (addIndex name 0)
, Leaving `with_` \case
Lam {} -> dropFrame
Let {} -> dropFrame
_ -> return ()
, Leaving `with_` \case
Bind (NameLet n) _ -> modify ([unName n] :)
, Leaving `with_` \case
Alt {} -> dropFrame
]
where
dropFrame = modify tail
main :: IO ()
main = do
print ast
-- assign initial De Brujin indices to names.
ast' <- runScopeM $ runTransform (descending @Prog useName) ast
print "----"
print ast'