"free" -> "leftfree" to try to reduce confusion.
Chris Pressey
26 days ago
338 | 338 |
### `abt`
|
339 | 339 |
|
340 | 340 |
Quoted literal ABTs are allowed to have free variables. The `abt` form take a list of
|
341 | |
variables that are considered free in the ABT expression. `quote` is actually a special
|
342 | |
case of `abt` where the set of free variables is empty.
|
|
341 |
variables that are to be considered free in the ABT expression. We call these variables
|
|
342 |
"variables left free" to distinguish them from when we use the term "free variables" to
|
|
343 |
describe variables that we have discovered to have no bindings (a perhaps more traditional
|
|
344 |
usage of "free").
|
|
345 |
|
|
346 |
`quote` is actually a special case of `abt` where the set of variables left free is empty.
|
343 | 347 |
|
344 | 348 |
(abt (x) x)
|
345 | |
===> <ABT: Operator "free" [Binder "x" (Var "x")]>
|
346 | |
|
347 | |
ABTs with free variables can't be `eval`'ed.
|
|
349 |
===> <ABT: Operator "leftfree" [Binder "x" (Var "x")]>
|
|
350 |
|
|
351 |
ABTs with variables left free can't be `eval`'ed.
|
348 | 352 |
|
349 | 353 |
(eval (abt (x) x))
|
350 | 354 |
???> Cannot eval
|
351 | 355 |
|
352 | |
The free variables declared don't actually have to appear.
|
|
356 |
The variables that we declare to have been left free, don't actually have to appear in
|
|
357 |
the expression.
|
353 | 358 |
|
354 | 359 |
(abt (x) 1)
|
355 | |
===> <ABT: Operator "free" [Binder "x" (Operator "literal" [Operator "1" []])]>
|
356 | |
|
357 | |
But an ABT with free variables that don't actually appear still can't be `eval`'ed.
|
|
360 |
===> <ABT: Operator "leftfree" [Binder "x" (Operator "literal" [Operator "1" []])]>
|
|
361 |
|
|
362 |
But an ABT with variables left free still can't be `eval`'ed, even if those variables
|
|
363 |
don't actually appear in it.
|
358 | 364 |
|
359 | 365 |
(eval (abt (x) 1))
|
360 | 366 |
???> Cannot eval
|
94 | 94 |
Operator "values" (map (\val -> performSubstitution val n k) vals)
|
95 | 95 |
]
|
96 | 96 |
|
97 | |
-- Handle free variables
|
98 | |
Operator "free" [Binder var body] ->
|
|
97 |
-- Handle leftfree variables
|
|
98 |
Operator "leftfree" [Binder var body] ->
|
99 | 99 |
if var == n
|
100 | 100 |
then performSubstitution body n k -- This free var is being substituted
|
101 | |
else Operator "free" [Binder var (performSubstitution body n k)]
|
|
101 |
else Operator "leftfree" [Binder var (performSubstitution body n k)]
|
102 | 102 |
|
103 | 103 |
-- Base cases
|
104 | 104 |
Var x | x == n -> k
|
51 | 51 |
scope <- ask
|
52 | 52 |
return $ Right (Operator "literal" [Operator ("string:" ++ s) []], scope)
|
53 | 53 |
|
54 | |
Quote fvars body -> do
|
|
54 |
Quote leftFreeVars body -> do
|
55 | 55 |
scope <- ask
|
56 | |
-- Put the free variables in scope before converting the body
|
|
56 |
-- Put the left-free variables in scope before converting the body
|
57 | 57 |
let scopeWithFreeVars = scope {
|
58 | |
boundVars = Set.union (boundVars scope) (Set.fromList fvars)
|
|
58 |
boundVars = Set.union (boundVars scope) (Set.fromList leftFreeVars)
|
59 | 59 |
}
|
60 | 60 |
-- Convert the body with the extended scope
|
61 | 61 |
case runReader (convertAST body) scopeWithFreeVars of
|
|
64 | 64 |
let finalScope = scope {
|
65 | 65 |
boundVars = boundVars scope, -- Don't persist the temporary free vars
|
66 | 66 |
freeVars = Set.union (freeVars scope)
|
67 | |
(Set.difference (freeVars bodyScope) (Set.fromList fvars))
|
|
67 |
(Set.difference (freeVars bodyScope) (Set.fromList leftFreeVars))
|
68 | 68 |
}
|
69 | |
abt = if fvars == []
|
|
69 |
abt = if leftFreeVars == []
|
70 | 70 |
then Operator "literal" [bodyABT]
|
71 | |
else Operator "literal" [Operator "free" [foldr Binder bodyABT fvars]]
|
|
71 |
else Operator "literal" [Operator "leftfree" [foldr Binder bodyABT leftFreeVars]]
|
72 | 72 |
in return $ Right (abt, finalScope)
|
73 | 73 |
|
74 | 74 |
Op name args -> do
|
30 | 30 |
env <- ask
|
31 | 31 |
return $ VClosure param body env
|
32 | 32 |
|
33 | |
Operator "free" [body] ->
|
34 | |
-- Regular evaluation only works on ABTs without "free" at the top
|
|
33 |
Operator "leftfree" [body] ->
|
|
34 |
-- Evaluation can only happen on ABTs without free variables
|
35 | 35 |
throwError "Cannot evaluate ABT with free variables"
|
36 | 36 |
|
37 | 37 |
Operator "apply" (fn:args) -> do
|
|
157 | 157 |
_ -> Left "subst: second argument must be a string"
|
158 | 158 |
_ -> Left "subst: first argument must be an ABT")
|
159 | 159 |
]
|
160 | |
where
|
161 | |
-- Helper function to perform the substitution
|
162 | 160 |
|
163 | 161 |
-- | Add transformers to initial environment
|
164 | 162 |
extendedInitialEnv :: Environment
|