21 KiB
21 KiB
In [1]:
import inspect
import joy.utils.stack
print inspect.getdoc(joy.utils.stack)§ Stack
When talking about Joy we use the terms "stack", "list", "sequence" and
"aggregate" to mean the same thing: a simple datatype that permits
certain operations such as iterating and pushing and popping values from
(at least) one end.
We use the venerable two-tuple recursive form of sequences where the
empty tuple () is the empty stack and (head, rest) gives the recursive
form of a stack with one or more items on it.
()
(1, ())
(2, (1, ()))
(3, (2, (1, ())))
...
And so on.
We have two very simple functions to build up a stack from a Python
iterable and also to iterate through a stack and yield its items
one-by-one in order, and two functions to generate string representations
of stacks:
list_to_stack()
iter_stack()
expression_to_string() (prints left-to-right)
stack_to_string() (prints right-to-left)
A word about the stack data structure.
Python has very nice "tuple packing and unpacking" in its syntax which
means we can directly "unpack" the expected arguments to a Joy function.
For example:
def dup(stack):
head, tail = stack
return head, (head, tail)
We replace the argument "stack" by the expected structure of the stack,
in this case "(head, tail)", and Python takes care of de-structuring the
incoming argument and assigning values to the names. Note that Python
syntax doesn't require parentheses around tuples used in expressions
where they would be redundant.
In [2]:
joy.utils.stack.list_to_stack([1, 2, 3])Out [2]:
(1, (2, (3, ())))
In [3]:
list(joy.utils.stack.iter_stack((1, (2, (3, ())))))Out [3]:
[1, 2, 3]
In [4]:
stack = ()
for n in [1, 2, 3]:
stack = n, stack
print stack
print list(joy.utils.stack.iter_stack(stack))(3, (2, (1, ()))) [3, 2, 1]
In [5]:
import joy.joy
print inspect.getsource(joy.joy.joy)def joy(stack, expression, dictionary, viewer=None):
'''
Evaluate the Joy expression on the stack.
'''
while expression:
if viewer: viewer(stack, expression)
term, expression = expression
if isinstance(term, Symbol):
term = dictionary[term]
stack, expression, dictionary = term(stack, expression, dictionary)
else:
stack = term, stack
if viewer: viewer(stack, expression)
return stack, expression, dictionary
In [6]:
import joy.parser
print inspect.getdoc(joy.parser)§ Converting text to a joy expression. This module exports a single function: text_to_expression(text) As well as a single Symbol class and a single Exception type: ParseError When supplied with a string this function returns a Python datastructure that represents the Joy datastructure described by the text expression. Any unbalanced square brackets will raise a ParseError.
In [7]:
print inspect.getsource(joy.parser._parse)def _parse(tokens):
'''
Return a stack/list expression of the tokens.
'''
frame = []
stack = []
for tok in tokens:
if tok == '[':
stack.append(frame)
frame = []
stack[-1].append(frame)
elif tok == ']':
try:
frame = stack.pop()
except IndexError:
raise ParseError('One or more extra closing brackets.')
frame[-1] = list_to_stack(frame[-1])
else:
frame.append(tok)
if stack:
raise ParseError('One or more unclosed brackets.')
return list_to_stack(frame)
In [8]:
joy.parser.text_to_expression('1 2 3 4 5') # A simple sequence.Out [8]:
(1, (2, (3, (4, (5, ())))))
In [9]:
joy.parser.text_to_expression('[1 2 3] 4 5') # Three items, the first is a list with three itemsOut [9]:
((1, (2, (3, ()))), (4, (5, ())))
In [10]:
joy.parser.text_to_expression('1 23 ["four" [-5.0] cons] 8888') # A mixed bag. cons is
# a Symbol, no lookup at
# parse-time. Haiku docs.Out [10]:
(1, (23, (('four', ((-5.0, ()), (cons, ()))), (8888, ()))))In [11]:
joy.parser.text_to_expression('[][][][][]') # Five empty lists.Out [11]:
((), ((), ((), ((), ((), ())))))
In [12]:
joy.parser.text_to_expression('[[[[[]]]]]') # Five nested lists.Out [12]:
((((((), ()), ()), ()), ()), ())
In [13]:
import joy.library
print ' '.join(sorted(joy.library.initialize()))!= % & * *fraction *fraction0 + ++ - -- / < << <= <> = > >= >> ? ^ add anamorphism and app1 app2 app3 average b binary branch choice clear cleave concat cons dinfrirst dip dipd dipdd disenstacken div down_to_zero dudipd dup dupd dupdip enstacken eq first flatten floordiv gcd ge genrec getitem gt help i id ifte infra le least_fraction loop lshift lt map min mod modulus mul ne neg not nullary or over pam parse pm pop popd popdd popop pow pred primrec product quoted range range_to_zero rem remainder remove rest reverse roll< roll> rolldown rollup rshift run second select sharing shunt size sqr sqrt stack step sub succ sum swaack swap swoncat swons ternary third times truediv truthy tuck unary uncons unit unquoted unstack void warranty while words x xor zip •
In [14]:
print inspect.getsource(joy.library.dip)def dip(stack, expression, dictionary): (quote, (x, stack)) = stack expression = x, expression return stack, pushback(quote, expression), dictionary
In [15]:
print joy.library.definitionssecond == rest first third == rest rest first product == 1 swap [*] step swons == swap cons swoncat == swap concat flatten == [] swap [concat] step unit == [] cons quoted == [unit] dip unquoted == [i] dip enstacken == stack [clear] dip disenstacken == ? [uncons ?] loop pop ? == dup truthy dinfrirst == dip infra first nullary == [stack] dinfrirst unary == [stack [pop] dip] dinfrirst binary == [stack [popop] dip] dinfrirst ternary == [stack [popop pop] dip] dinfrirst pam == [i] map run == [] swap infra sqr == dup mul size == 0 swap [pop ++] step cleave == [i] app2 [popd] dip average == [sum 1.0 *] [size] cleave / gcd == 1 [tuck modulus dup 0 >] loop pop least_fraction == dup [gcd] infra [div] concat map *fraction == [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons *fraction0 == concat [[swap] dip * [*] dip] infra down_to_zero == [0 >] [dup --] while range_to_zero == unit [down_to_zero] infra anamorphism == [pop []] swap [dip swons] genrec range == [0 <=] [1 - dup] anamorphism while == swap [nullary] cons dup dipd concat loop dudipd == dup dipd primrec == [i] genrec
In [ ]: