Skip to content

Commit

Permalink
feat: special forms
Browse files Browse the repository at this point in the history
  • Loading branch information
Leslie-Jiang-Hamster committed Jan 22, 2024
1 parent 5f33bef commit 78c22ad
Show file tree
Hide file tree
Showing 15 changed files with 176 additions and 193 deletions.
7 changes: 6 additions & 1 deletion scheme_classes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import builtins

from pair import *
from util import *

class SchemeError(Exception):
"""Exception indicating an error in a Scheme program."""
Expand Down Expand Up @@ -54,7 +55,11 @@ def make_child_frame(self, formals, vals):
if len(formals) != len(vals):
raise SchemeError('Incorrect number of arguments to function call')
# BEGIN PROBLEM 8
"*** YOUR CODE HERE ***"
formals = pair_to_list(formals)
vals = pair_to_list(vals)
new_frame = Frame(self)
map_(iota(len(formals)), lambda i: new_frame.define(formals[i], vals[i]))
return new_frame
# END PROBLEM 8

##############
Expand Down
11 changes: 8 additions & 3 deletions scheme_eval_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ def scheme_apply(procedure, args, env):
raise SchemeError('incorrect number of arguments: {0}'.format(procedure))
elif isinstance(procedure, LambdaProcedure):
# BEGIN PROBLEM 9
"*** YOUR CODE HERE ***"
new_frame = procedure.env.make_child_frame(procedure.formals, args)
return eval_all(procedure.body, new_frame)
# END PROBLEM 9
elif isinstance(procedure, MuProcedure):
# BEGIN PROBLEM 11
"*** YOUR CODE HERE ***"
new_frame = env.make_child_frame(procedure.formals, args)
return eval_all(procedure.body, new_frame)
# END PROBLEM 11
else:
assert False, "Unexpected procedure: {}".format(procedure)
Expand All @@ -85,7 +87,10 @@ def eval_all(expressions, env):
2
"""
# BEGIN PROBLEM 6
return scheme_eval(expressions.first, env) # replace this with lines of your own code
if expressions == nil:
return None
map_(except_last(expressions), lambda x: scheme_eval(x, env))
return scheme_eval(last(expressions), env)
# END PROBLEM 6


Expand Down
53 changes: 44 additions & 9 deletions scheme_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from scheme_utils import *
from scheme_classes import *
from scheme_builtins import *
from util import *

#################
# Special Forms #
Expand Down Expand Up @@ -36,12 +37,20 @@ def do_define_form(expressions, env):
# assigning a name to a value e.g. (define x (+ 1 2))
validate_form(expressions, 2, 2) # Checks that expressions is a list of length exactly 2
# BEGIN PROBLEM 4
"*** YOUR CODE HERE ***"
expr = expressions.rest.first
val = scheme_eval(expr, env)
env.define(signature, val)
return signature
# END PROBLEM 4
elif isinstance(signature, Pair) and scheme_symbolp(signature.first):
# defining a named procedure e.g. (define (f x y) (+ x y))
# BEGIN PROBLEM 10
"*** YOUR CODE HERE ***"
symbol = signature.first
formals = signature.rest
body = expressions.rest
lambda_ = do_lambda_form(Pair(formals, body), env)
env.define(symbol, lambda_)
return symbol
# END PROBLEM 10
else:
bad_signature = signature.first if isinstance(signature, Pair) else signature
Expand All @@ -56,7 +65,8 @@ def do_quote_form(expressions, env):
"""
validate_form(expressions, 1, 1)
# BEGIN PROBLEM 5
"*** YOUR CODE HERE ***"
quoted = expressions.first
return quoted
# END PROBLEM 5

def do_begin_form(expressions, env):
Expand All @@ -82,7 +92,8 @@ def do_lambda_form(expressions, env):
formals = expressions.first
validate_formals(formals)
# BEGIN PROBLEM 7
"*** YOUR CODE HERE ***"
body = expressions.rest
return LambdaProcedure(formals, body, env)
# END PROBLEM 7

def do_if_form(expressions, env):
Expand Down Expand Up @@ -115,7 +126,14 @@ def do_and_form(expressions, env):
False
"""
# BEGIN PROBLEM 12
"*** YOUR CODE HERE ***"
if expressions == nil:
return True
first_val = scheme_eval(expressions.first, env)
if len(expressions) == 1:
return first_val
if is_scheme_false(first_val):
return first_val
return do_and_form(expressions.rest, env)
# END PROBLEM 12

def do_or_form(expressions, env):
Expand All @@ -133,7 +151,14 @@ def do_or_form(expressions, env):
6
"""
# BEGIN PROBLEM 12
"*** YOUR CODE HERE ***"
if expressions == nil:
return False
first_val = scheme_eval(expressions.first, env)
if len(expressions) == 1:
return first_val
if is_scheme_true(first_val):
return first_val
return do_or_form(expressions.rest, env)
# END PROBLEM 12

def do_cond_form(expressions, env):
Expand All @@ -153,7 +178,9 @@ def do_cond_form(expressions, env):
test = scheme_eval(clause.first, env)
if is_scheme_true(test):
# BEGIN PROBLEM 13
"*** YOUR CODE HERE ***"
if clause.rest == nil:
return test
return eval_all(clause.rest, env)
# END PROBLEM 13
expressions = expressions.rest

Expand All @@ -177,7 +204,13 @@ def make_let_frame(bindings, env):
raise SchemeError('bad bindings list in let form')
names = vals = nil
# BEGIN PROBLEM 14
"*** YOUR CODE HERE ***"
bindings = pair_to_list(bindings)
map_(bindings, lambda kv: validate_form(kv, 2, 2))
names = map_(bindings, lambda kv: kv.first)
names = list_to_pair(names)
validate_formals(names)
vals = map_(bindings, lambda kv: scheme_eval(second(kv), env))
vals = list_to_pair(vals)
# END PROBLEM 14
return env.make_child_frame(names, vals)

Expand Down Expand Up @@ -219,7 +252,9 @@ def do_mu_form(expressions, env):
formals = expressions.first
validate_formals(formals)
# BEGIN PROBLEM 11
"*** YOUR CODE HERE ***"
body = expressions.rest
mu = MuProcedure(formals, body)
return mu
# END PROBLEM 11


Expand Down
22 changes: 9 additions & 13 deletions tests/04.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
'cases': [
{
'answer': 'e92e90f58a272e7a74651635251ade14',
'answer': 'Pair(A, Pair(B, nil)), where: A is the symbol being bound, B is an expression whose value should be evaluated and bound to A',
'choices': [
r"""
Pair(A, Pair(B, nil)), where:
Expand Down Expand Up @@ -34,20 +34,20 @@
"""
],
'hidden': False,
'locked': True,
'locked': False,
'multiline': False,
'question': 'What is the structure of the expressions argument to do_define_form?'
},
{
'answer': '0ed53dce7bacc4766422abc478c5c895',
'answer': 'define',
'choices': [
'make_child_frame',
'define',
'lookup',
'bindings'
],
'hidden': False,
'locked': True,
'locked': False,
'multiline': False,
'question': r"""
What method of a Frame instance will bind
Expand All @@ -63,20 +63,16 @@
{
'code': r"""
scm> (define size 2)
cc3c061fb8167d02a4ddda1f1c19966e
# locked
size
scm> size
2b7cdec3904f986982cbd24a0bc12887
# locked
2
scm> (define x (+ 7 3))
38ba916dc1f41eb239567ee41a251ecd
# locked
x
scm> x
4bc2fb48972a5d1ec1201b01e766a044
# locked
10
""",
'hidden': False,
'locked': True,
'locked': False,
'multiline': False
},
{
Expand Down
15 changes: 6 additions & 9 deletions tests/05.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
'cases': [
{
'answer': 'fd4dd892ccea3adcf9446dc4a9738d47',
'answer': 'Pair(A, nil), where: A is the quoted expression',
'choices': [
r"""
Pair('quote', Pair(A, nil)), where:
Expand All @@ -25,7 +25,7 @@
"""
],
'hidden': False,
'locked': True,
'locked': False,
'multiline': False,
'question': 'What is the structure of the expressions argument to do_quote_form?'
}
Expand All @@ -38,18 +38,15 @@
{
'code': r"""
>>> do_quote_form(Pair(3, nil), global_frame)
3c7e8a3a2176a696c3a66418f78dff6b
# locked
3
>>> do_quote_form(Pair('hi', nil), global_frame)
95448591e64e04a7a7885d5fb9b45583
# locked
'hi'
>>> expr = Pair(Pair('+', Pair('x', Pair(2, nil))), nil)
>>> do_quote_form(expr, global_frame) # Make sure to use Pair notation
2301ee746b57783004f00f39498fdaed
# locked
Pair('+', Pair('x', Pair(2, nil)))
""",
'hidden': False,
'locked': True,
'locked': False,
'multiline': False
}
],
Expand Down
43 changes: 12 additions & 31 deletions tests/06.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,13 @@
{
'code': r"""
>>> eval_all(Pair(2, nil), env)
2b7cdec3904f986982cbd24a0bc12887
# locked
# choice: 2
# choice: SchemeError
2
>>> eval_all(Pair(4, Pair(5, nil)), env)
b33c0f7206201b4aaeae595493888600
# locked
# choice: 4
# choice: 5
# choice: (4 5)
# choice: SchemeError
5
>>> eval_all(nil, env) # return None (meaning undefined)
""",
'hidden': False,
'locked': True,
'locked': False,
'multiline': False
},
{
Expand Down Expand Up @@ -50,40 +42,29 @@
{
'code': r"""
scm> (begin (+ 2 3) (+ 5 6))
20169e9f217f8370ba4f37a3cf0cc2b3
# locked
11
scm> (begin (define x 3) x)
3c7e8a3a2176a696c3a66418f78dff6b
# locked
3
""",
'hidden': False,
'locked': True,
'locked': False,
'multiline': False
},
{
'code': r"""
scm> (begin 30 '(+ 2 2))
85d97cf58c044cc51a6a7d4315b4ad71
# locked
# choice: (+ 2 2)
# choice: '(+ 2 2)
# choice: 4
# choice: 30
(+ 2 2)
scm> (define x 0)
38ba916dc1f41eb239567ee41a251ecd
# locked
x
scm> (begin (define x (+ x 1)) 42 (define y (+ x 1)))
1a9a3321b8b99a0f9291d89be986e74c
# locked
y
scm> x
eb892a26497f936d1f6cae54aacc5f51
# locked
1
scm> y
2b7cdec3904f986982cbd24a0bc12887
# locked
2
""",
'hidden': False,
'locked': True,
'locked': False,
'multiline': False
},
{
Expand Down
23 changes: 6 additions & 17 deletions tests/07.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@
{
'code': r"""
scm> (lambda (x y) (+ x y)) ;; An lambda procedure is displayed exactly as it is written
1456de84c3edf333b6f7aee0c0624b20
# locked
(lambda (x y) (+ x y))
scm> (lambda (x)) ; type SchemeError if you think this causes an error
ec908af60f03727428c7ee3f22ec3cd8
# locked
SchemeError
""",
'hidden': False,
'locked': True,
'locked': False,
'multiline': False
},
{
Expand Down Expand Up @@ -49,21 +47,12 @@
>>> lambda_line = read_line("(lambda (a b c) (+ a b c))")
>>> lambda_proc = do_lambda_form(lambda_line.rest, env)
>>> lambda_proc.formals # use single quotes ' around strings in your answer
d106bb7be6b014a9d16d74410be4a8a5
# locked
# choice: Pair('a', Pair('b', Pair('c', nil)))
# choice: Pair('+', Pair('a', Pair('b', Pair('c', nil))))
# choice: Pair(Pair('a', Pair('b', Pair('c', nil))))
Pair('a', Pair('b', Pair('c', nil)))
>>> lambda_proc.body # the body is a *Scheme list* of expressions! Make sure your answer is a properly nested Pair.
0ef147cfe5caf670e985d95d923f4b06
# locked
# choice: Pair(Pair('+', Pair('a', Pair('b', Pair('c', nil)))), nil)
# choice: Pair('+', Pair('a', Pair('b', Pair('c', nil))))
# choice: Pair('+', 'a', 'b', 'c')
# choice: Pair('a', Pair('b', Pair('c')))
Pair(Pair('+', Pair('a', Pair('b', Pair('c', nil)))), nil)
""",
'hidden': False,
'locked': True,
'locked': False,
'multiline': False
},
{
Expand Down
Loading

0 comments on commit 78c22ad

Please sign in to comment.