Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f0f1608

Browse files
committed
sync with O'Reilly Atlas
1 parent e986e3b commit f0f1608

File tree

26 files changed

+308
-1004
lines changed

26 files changed

+308
-1004
lines changed

‎02-array-seq/lispy/examples_test.py‎

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""
2+
Doctests for `parse`:
3+
4+
>>> from lis import parse
5+
6+
# tag::PARSE_DEMO[]
7+
>>> parse('1.5') # <1>
8+
1.5
9+
>>> parse('set!') # <2>
10+
'set!'
11+
>>> parse('(gcd 18 44)') # <3>
12+
['gcd', 18, 44]
13+
>>> parse('(- m (* n (// m n)))') # <4>
14+
['-', 'm', ['*', 'n', ['//', 'm', 'n']]]
15+
16+
# end::PARSE_DEMO[]
17+
18+
"""
19+
20+
import math
21+
22+
from lis import run
23+
24+
25+
fact_src = """
26+
(define (! n)
27+
(if (< n 2)
28+
1
29+
(* n (! (- n 1)))
30+
)
31+
)
32+
(! 42)
33+
"""
34+
def test_factorial():
35+
got = run(fact_src)
36+
assert got == 1405006117752879898543142606244511569936384000000000
37+
assert got == math.factorial(42)
38+
39+
40+
gcd_src = """
41+
(define (mod m n)
42+
(- m (* n (// m n))))
43+
(define (gcd m n)
44+
(if (= n 0)
45+
m
46+
(gcd n (mod m n))))
47+
(gcd 18 45)
48+
"""
49+
def test_gcd():
50+
got = run(gcd_src)
51+
assert got == 9
52+
53+
54+
quicksort_src = """
55+
(define (quicksort lst)
56+
(if (null? lst)
57+
lst
58+
(begin
59+
(define pivot (car lst))
60+
(define rest (cdr lst))
61+
(append
62+
(quicksort
63+
(filter (lambda (x) (< x pivot)) rest))
64+
(list pivot)
65+
(quicksort
66+
(filter (lambda (x) (>= x pivot)) rest)))
67+
)
68+
)
69+
)
70+
(quicksort (list 2 1 6 3 4 0 8 9 7 5))
71+
"""
72+
def test_quicksort():
73+
got = run(quicksort_src)
74+
assert got == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
75+
76+
77+
# Example from Structure and Interpretation of Computer Programs
78+
# https://mitpress.mit.edu/sites/default/files/sicp/full-text/sicp/book/node12.html
79+
80+
newton_src = """
81+
(define (sqrt x)
82+
(sqrt-iter 1.0 x))
83+
(define (sqrt-iter guess x)
84+
(if (good-enough? guess x)
85+
guess
86+
(sqrt-iter (improve guess x) x)))
87+
(define (good-enough? guess x)
88+
(< (abs (- (* guess guess) x)) 0.001))
89+
(define (improve guess x)
90+
(average guess (/ x guess)))
91+
(define (average x y)
92+
(/ (+ x y) 2))
93+
(sqrt 123454321)
94+
"""
95+
def test_newton():
96+
got = run(newton_src)
97+
assert math.isclose(got, 11111)
98+
99+
100+
closure_src = """
101+
(define (make-adder increment)
102+
(lambda (x) (+ increment x))
103+
)
104+
(define inc (make-adder 1))
105+
(inc 99)
106+
"""
107+
def test_newton():
108+
got = run(closure_src)
109+
assert got == 100

‎18-context-mngr/lispy/py3.10/lis.py‎ renamed to ‎02-array-seq/lispy/lis.py‎

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
################ Lispy: Scheme Interpreter in Python 3.9
1+
################ Lispy: Scheme Interpreter in Python 3.10
22

33
## (c) Peter Norvig, 2010-18; See http://norvig.com/lispy.html
44
## Minor edits for Fluent Python, Second Edition (O'Reilly, 2021)
55
## by Luciano Ramalho, adding type hints and pattern matching.
66

7-
################ Imports and Types
7+
################ imports and types
88

99
import math
1010
import operator as op
1111
from collections import ChainMap
12-
from collections.abc import MutableMapping
12+
from collections.abc import MutableMapping, Iterator
13+
from itertools import chain
1314
from typing import Any, TypeAlias
1415

1516
Symbol: TypeAlias = str
@@ -23,41 +24,44 @@ class Procedure:
2324
"A user-defined Scheme procedure."
2425

2526
def __init__(self, parms: list[Symbol], body: Expression, env: Environment):
26-
self.parms, self.body, self.env = parms, body, env
27+
self.parms = parms
28+
self.body = body
29+
self.env = env
2730

2831
def __call__(self, *args: Expression) -> Any:
2932
local_env = dict(zip(self.parms, args))
3033
env: Environment = ChainMap(local_env, self.env)
3134
return evaluate(self.body, env)
3235

3336

34-
################ Global Environment
37+
################ global environment
3538

3639

3740
def standard_env() -> Environment:
3841
"An environment with some Scheme standard procedures."
3942
env: Environment = {}
4043
env.update(vars(math)) # sin, cos, sqrt, pi, ...
41-
env.update(
42-
{
44+
env.update({
4345
'+': op.add,
4446
'-': op.sub,
4547
'*': op.mul,
4648
'/': op.truediv,
49+
'//': op.floordiv,
4750
'>': op.gt,
4851
'<': op.lt,
4952
'>=': op.ge,
5053
'<=': op.le,
5154
'=': op.eq,
5255
'abs': abs,
53-
'append': op.add,
56+
'append': lambda*args: list(chain(*args)),
5457
'apply': lambda proc, args: proc(*args),
5558
'begin': lambda *x: x[-1],
5659
'car': lambda x: x[0],
5760
'cdr': lambda x: x[1:],
5861
'cons': lambda x, y: [x] + y,
5962
'eq?': op.is_,
6063
'equal?': op.eq,
64+
'filter': lambda *args: list(filter(*args)),
6165
'length': len,
6266
'list': lambda *x: list(x),
6367
'list?': lambda x: isinstance(x, list),
@@ -70,12 +74,11 @@ def standard_env() -> Environment:
7074
'procedure?': callable,
7175
'round': round,
7276
'symbol?': lambda x: isinstance(x, Symbol),
73-
}
74-
)
77+
})
7578
return env
7679

7780

78-
################ Parsing: parse, tokenize, and read_from_tokens
81+
################ parse, tokenize, and read_from_tokens
7982

8083

8184
def parse(program: str) -> Expression:
@@ -94,11 +97,11 @@ def read_from_tokens(tokens: list[str]) -> Expression:
9497
raise SyntaxError('unexpected EOF while reading')
9598
token = tokens.pop(0)
9699
if '(' == token:
97-
L = []
100+
exp = []
98101
while tokens[0] != ')':
99-
L.append(read_from_tokens(tokens))
100-
tokens.pop(0) # pop off ')'
101-
return L
102+
exp.append(read_from_tokens(tokens))
103+
tokens.pop(0) # discard ')'
104+
return exp
102105
elif ')' == token:
103106
raise SyntaxError('unexpected )')
104107
else:
@@ -116,7 +119,7 @@ def parse_atom(token: str) -> Atom:
116119
return Symbol(token)
117120

118121

119-
################ Interaction: A REPL
122+
################ interaction: a REPL
120123

121124

122125
def repl(prompt: str = 'lis.py> ') -> None:
@@ -138,29 +141,50 @@ def lispstr(exp: object) -> str:
138141

139142
################ eval
140143

141-
142-
def evaluate(x: Expression, env: Environment) -> Any:
144+
# tag::EVALUATE[]
145+
def evaluate(exp: Expression, env: Environment) -> Any:
143146
"Evaluate an expression in an environment."
144-
match x:
145-
case Symbol(var): # variable reference
147+
match exp:
148+
case int(x) | float(x):
149+
return x
150+
case Symbol(var):
146151
return env[var]
147-
case literalifnotisinstance(x, list): # constant literal
148-
return literal
149-
case ['quote', exp]:# (quote exp)
152+
case []:
153+
return []
154+
case ['quote', exp]:
150155
return exp
151-
case ['if', test, conseq, alt]: # (if test conseq alt)
156+
case ['if', test, consequence, alternative]:
152157
if evaluate(test, env):
153-
exp=conseq
158+
returnevaluate(consequence, env)
154159
else:
155-
exp = alt
156-
return evaluate(exp, env)
157-
case ['lambda', parms, body]: # (lambda (parm...) body)
158-
return Procedure(parms, body, env)
159-
case ['define', Symbol(var), exp]: # (define var exp)
160-
env[var] = evaluate(exp, env)
161-
case ['define', [name, *parms], body]: # (define (fun parm...) body)
160+
return evaluate(alternative, env)
161+
case ['define', Symbol(var), value_exp]:
162+
env[var] = evaluate(value_exp, env)
163+
case ['define', [Symbol(name), *parms], body]:
162164
env[name] = Procedure(parms, body, env)
163-
case [op, *args]: # (proc arg...)
165+
case ['lambda', [*parms], body]:
166+
return Procedure(parms, body, env)
167+
case [op, *args]:
164168
proc = evaluate(op, env)
165-
values = (evaluate(arg, env) for arg in args)
169+
values = [evaluate(arg, env) for arg in args]
166170
return proc(*values)
171+
case _:
172+
raise SyntaxError(repr(exp))
173+
# end::EVALUATE[]
174+
175+
176+
################ non-interactive execution
177+
178+
179+
def run_lines(source: str) -> Iterator[Any]:
180+
global_env: Environment = standard_env()
181+
tokens = tokenize(source)
182+
while tokens:
183+
exp = read_from_tokens(tokens)
184+
yield evaluate(exp, global_env)
185+
186+
187+
def run(source: str) -> Any:
188+
for result in run_lines(source):
189+
pass
190+
return result

‎18-context-mngr/lispy/py3.10/lis_test.py‎ renamed to ‎02-array-seq/lispy/lis_test.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@
44

55
from lis import parse, evaluate, Expression, Environment, standard_env
66

7+
############################################################# tests for parse
8+
9+
@mark.parametrize( 'source, expected', [
10+
('7', 7),
11+
('x', 'x'),
12+
('(sum 1 2 3)', ['sum', 1, 2, 3]),
13+
('(+ (* 2 100) (* 1 10))', ['+', ['*', 2, 100], ['*', 1, 10]]),
14+
('99 100', 99), # parse stops at the first complete expression
15+
('(a)(b)', ['a']),
16+
])
17+
def test_parse(source: str, expected: Expression) -> None:
18+
got = parse(source)
19+
assert got == expected
20+
21+
22+
########################################################## tests for evaluate
23+
724
# Norvig's tests are not isolated: they assume the
825
# same environment from first to last test.
926
global_env_for_first_test = standard_env()

‎02-array-seq/lispy/meta_test.py‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import operator as op
2+
3+
from lis import run
4+
5+
env_scm = """
6+
(define standard-env (list
7+
(list (quote +) +)
8+
(list (quote -) -)
9+
))
10+
standard-env
11+
"""
12+
13+
def test_env_build():
14+
got = run(env_scm)
15+
assert got == [['+', op.add], ['-', op.sub]]
16+
17+
scan_scm = """
18+
(define l (quote (a b c)))
19+
(define (scan what where)
20+
(if (null? where)
21+
()
22+
(if (eq? what (car where))
23+
what
24+
(scan what (cdr where))))
25+
)
26+
"""
27+
28+
def test_scan():
29+
source = scan_scm + '(scan (quote a) l )'
30+
got = run(source)
31+
assert got == 'a'
32+
33+
34+
def test_scan_not_found():
35+
source = scan_scm + '(scan (quote z) l )'
36+
got = run(source)
37+
assert got == []
38+
39+
40+
lookup_scm = """
41+
(define env (list
42+
(list (quote +) +)
43+
(list (quote -) -)
44+
))
45+
(define (lookup what where)
46+
(if (null? where)
47+
()
48+
(if (eq? what (car (car where)))
49+
(car (cdr (car where)))
50+
(lookup what (cdr where))))
51+
)
52+
"""
53+
54+
def test_lookup():
55+
source = lookup_scm + '(lookup (quote +) env)'
56+
got = run(source)
57+
assert got == op.add
58+
59+
60+
def test_lookup_not_found():
61+
source = lookup_scm + '(lookup (quote z) env )'
62+
got = run(source)
63+
assert got == []
64+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /