@@ -11,6 +11,7 @@ pub type Expression {
11
11
Int ( Int )
12
12
Atom ( String )
13
13
Procedure ( procedure : Procedure )
14
+ Closure ( arguments : List ( String ) , body : List ( Expression ) , scope : Scope )
14
15
}
15
16
16
17
pub type Error {
@@ -137,6 +138,7 @@ fn new_state() -> State {
137
138
#("or", Procedure(or_builtin)),
138
139
#("if", Procedure(if_builtin)),
139
140
#("define", Procedure(define_builtin)),
141
+ #("lambda", Procedure(lambda_builtin)),
140
142
])
141
143
let local_scope = map.new()
142
144
State(global_scope: global_scope, local_scope: local_scope)
@@ -158,7 +160,7 @@ fn evaluate(
158
160
159
161
fn evaluate_expression(expression: Expression, state: State) -> Evaluated {
160
162
case expression {
161
- Bool(_) | Int(_) | Procedure(..) -> Ok(#(expression, state))
163
+ Bool(_) | Int(_) | Procedure(_) | Closure( ..) -> Ok(#(expression, state))
162
164
List(expressions) -> evaluate_list(expressions, state)
163
165
Atom(atom) -> {
164
166
try value = evaluate_atom(atom, state)
@@ -198,7 +200,41 @@ fn call(
198
200
) -> Evaluated {
199
201
case callable {
200
202
Procedure(procedure) -> procedure(arguments, state)
201
- _ -> type_error("procedure", callable)
203
+ Closure(parameters, body, environment) ->
204
+ call_closure(parameters, body, environment, arguments, state)
205
+ _ -> type_error("Procedure", callable)
206
+ }
207
+ }
208
+
209
+ fn call_closure(
210
+ parameters: List(String),
211
+ body: List(Expression),
212
+ environment: Map(String, Expression),
213
+ arguments: List(Expression),
214
+ state: State,
215
+ ) -> Evaluated {
216
+ let original_locals = state.local_scope
217
+ let state = set_locals(state, environment)
218
+ try state = evaluate_lambda_arguments(parameters, arguments, state, 0)
219
+ try #(result, state) = evaluate(body, empty, state)
220
+ Ok(#(result, set_locals(state, original_locals)))
221
+ }
222
+
223
+ fn evaluate_lambda_arguments(
224
+ parameters: List(String),
225
+ arguments: List(Expression),
226
+ state: State,
227
+ count: Int,
228
+ ) -> Result(State, Error) {
229
+ case parameters, arguments {
230
+ [], [] -> Ok(state)
231
+ [parameter, ..parameters], [argument, ..arguments] -> {
232
+ try #(argument, state) = evaluate_expression(argument, state)
233
+ let state = insert_local(state, parameter, argument)
234
+ evaluate_lambda_arguments(parameters, arguments, state, count + 1)
235
+ }
236
+ [], rest -> Error(IncorrectArity(count, count + list.length(rest)))
237
+ rest, [] -> Error(IncorrectArity(count + list.length(rest), count))
202
238
}
203
239
}
204
240
@@ -225,6 +261,17 @@ fn define_builtin(arguments: List(Expression), state: State) -> Evaluated {
225
261
}
226
262
}
227
263
264
+ fn lambda_builtin(arguments: List(Expression), state: State) -> Evaluated {
265
+ case arguments {
266
+ [parameters, ..body] -> {
267
+ try parameters = expect_list(parameters)
268
+ try parameters = list.try_map(parameters, expect_atom)
269
+ Ok(#(Closure(parameters, body, state.local_scope), state))
270
+ }
271
+ _ -> Error(IncorrectArity(2, list.length(arguments)))
272
+ }
273
+ }
274
+
228
275
fn evaluate_atom(atom: String, state: State) -> Result(Expression, Error) {
229
276
map.get(state.local_scope, atom)
230
277
|> result.lazy_or(fn() { map.get(state.global_scope, atom) })
@@ -429,6 +476,7 @@ fn type_name(value: Expression) -> String {
429
476
Bool(_) -> "Bool"
430
477
List(_) -> "List"
431
478
Procedure(_) -> "Procedure"
479
+ Closure(..) -> "Closure"
432
480
Atom(_) -> "Atom"
433
481
}
434
482
}
@@ -440,6 +488,7 @@ fn print(value: Expression) -> String {
440
488
Bool(False) -> "false"
441
489
List(xs) -> "'(" <> string.join(list.map(xs, print), " ") <> ")"
442
490
Procedure(_) -> "#<procedure>"
491
+ Closure(..) -> "#<closure>"
443
492
Atom(x) -> "'" <> x
444
493
}
445
494
}
0 commit comments