Bringing over some of the "upgrades".
This commit is contained in:
@@ -7,322 +7,6 @@ ALIASES = (
|
||||
('id', [u'•']),
|
||||
)
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def inscribe_(stack, expression, dictionary):
|
||||
'''
|
||||
Create a new Joy function definition in the Joy dictionary. A
|
||||
definition is given as a quote with a name followed by a Joy
|
||||
expression. for example:
|
||||
|
||||
[sqr dup mul] inscribe
|
||||
|
||||
'''
|
||||
(name, body), stack = stack
|
||||
inscribe(Def(name, body), dictionary)
|
||||
return stack, expression, dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def getitem(stack):
|
||||
'''
|
||||
::
|
||||
|
||||
getitem == drop first
|
||||
|
||||
Expects an integer and a quote on the stack and returns the item at the
|
||||
nth position in the quote counting from 0.
|
||||
::
|
||||
|
||||
[a b c d] 0 getitem
|
||||
-------------------------
|
||||
a
|
||||
|
||||
'''
|
||||
n, (Q, stack) = stack
|
||||
return pick(Q, n), stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def drop(stack):
|
||||
'''
|
||||
::
|
||||
|
||||
drop == [rest] times
|
||||
|
||||
Expects an integer and a quote on the stack and returns the quote with
|
||||
n items removed off the top.
|
||||
::
|
||||
|
||||
[a b c d] 2 drop
|
||||
----------------------
|
||||
[c d]
|
||||
|
||||
'''
|
||||
n, (Q, stack) = stack
|
||||
while n > 0:
|
||||
try:
|
||||
_, Q = Q
|
||||
except ValueError:
|
||||
raise IndexError
|
||||
n -= 1
|
||||
return Q, stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def take(stack):
|
||||
'''
|
||||
Expects an integer and a quote on the stack and returns the quote with
|
||||
just the top n items in reverse order (because that's easier and you can
|
||||
use reverse if needed.)
|
||||
::
|
||||
|
||||
[a b c d] 2 take
|
||||
----------------------
|
||||
[b a]
|
||||
|
||||
'''
|
||||
n, (Q, stack) = stack
|
||||
x = ()
|
||||
while n > 0:
|
||||
try:
|
||||
item, Q = Q
|
||||
except ValueError:
|
||||
raise IndexError
|
||||
x = item, x
|
||||
n -= 1
|
||||
return x, stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def gcd2(stack, expression, dictionary):
|
||||
'''Compiled GCD function.'''
|
||||
(v1, (v2, stack)) = stack
|
||||
tos = True
|
||||
while tos:
|
||||
v3 = v2 % v1
|
||||
tos = v3 > 0
|
||||
(v1, (v2, stack)) = (v3, (v1, stack))
|
||||
return (v2, stack), expression, dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def choice(stack):
|
||||
'''
|
||||
Use a Boolean value to select one of two items.
|
||||
::
|
||||
|
||||
A B false choice
|
||||
----------------------
|
||||
A
|
||||
|
||||
|
||||
A B true choice
|
||||
---------------------
|
||||
B
|
||||
|
||||
'''
|
||||
(if_, (then, (else_, stack))) = stack
|
||||
assert isinstance(if_, bool), repr(if_)
|
||||
return then if if_ else else_, stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def select(stack):
|
||||
'''
|
||||
Use a Boolean value to select one of two items from a sequence.
|
||||
::
|
||||
|
||||
[A B] false select
|
||||
------------------------
|
||||
A
|
||||
|
||||
|
||||
[A B] true select
|
||||
-----------------------
|
||||
B
|
||||
|
||||
The sequence can contain more than two items but not fewer.
|
||||
Currently Python semantics are used to evaluate the "truthiness" of the
|
||||
Boolean value (so empty string, zero, etc. are counted as false, etc.)
|
||||
'''
|
||||
(flag, (choices, stack)) = stack
|
||||
(else_, (then, _)) = choices
|
||||
return then if flag else else_, stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def max_(S):
|
||||
'''Given a list find the maximum.'''
|
||||
tos, stack = S
|
||||
return max(iter_stack(tos)), stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def min_(S):
|
||||
'''Given a list find the minimum.'''
|
||||
tos, stack = S
|
||||
return min(iter_stack(tos)), stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def sum_(S):
|
||||
'''
|
||||
Given a quoted sequence of numbers return the sum.
|
||||
::
|
||||
|
||||
sum == 0 swap [+] step
|
||||
|
||||
'''
|
||||
tos, stack = S
|
||||
return sum(iter_stack(tos)), stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def remove(S):
|
||||
'''
|
||||
Expects an item on the stack and a quote under it and removes that item
|
||||
from the the quote. The item is only removed once. If the list is
|
||||
empty or the item isn't in the list then the list is unchanged.
|
||||
::
|
||||
|
||||
[1 2 3 1] 1 remove
|
||||
------------------------
|
||||
[2 3 1]
|
||||
|
||||
'''
|
||||
(item, (quote, stack)) = S
|
||||
return _remove(item, quote), stack
|
||||
|
||||
|
||||
def _remove(item, quote):
|
||||
try: head, tail = quote
|
||||
except ValueError: return quote
|
||||
return tail if head == item else (head, _remove(item, tail))
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def unique(S):
|
||||
'''Given a list remove duplicate items.'''
|
||||
tos, stack = S
|
||||
I = list(iter_stack(tos))
|
||||
return list_to_stack(sorted(set(I), key=I.index)), stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def sort_(S):
|
||||
'''Given a list return it sorted.'''
|
||||
tos, stack = S
|
||||
return list_to_stack(sorted(iter_stack(tos))), stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def disenstacken(stack):
|
||||
'''
|
||||
The disenstacken operator expects a list on top of the stack and makes that
|
||||
the stack discarding the rest of the stack.
|
||||
'''
|
||||
return stack[0]
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def reverse(S):
|
||||
'''
|
||||
Reverse the list on the top of the stack.
|
||||
::
|
||||
|
||||
reverse == [] swap shunt
|
||||
'''
|
||||
(tos, stack) = S
|
||||
res = ()
|
||||
for term in iter_stack(tos):
|
||||
res = term, res
|
||||
return res, stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def shunt(stack):
|
||||
'''
|
||||
Like concat but reverses the top list into the second.
|
||||
::
|
||||
|
||||
shunt == [swons] step == reverse swap concat
|
||||
|
||||
[a b c] [d e f] shunt
|
||||
---------------------------
|
||||
[f e d a b c]
|
||||
|
||||
'''
|
||||
(tos, (second, stack)) = stack
|
||||
while tos:
|
||||
term, tos = tos
|
||||
second = term, second
|
||||
return second, stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def zip_(S):
|
||||
'''
|
||||
Replace the two lists on the top of the stack with a list of the pairs
|
||||
from each list. The smallest list sets the length of the result list.
|
||||
'''
|
||||
(tos, (second, stack)) = S
|
||||
accumulator = [
|
||||
(a, (b, ()))
|
||||
for a, b in zip(iter_stack(tos), iter_stack(second))
|
||||
]
|
||||
return list_to_stack(accumulator), stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def succ(S):
|
||||
'''Increment TOS.'''
|
||||
(tos, stack) = S
|
||||
return tos + 1, stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def pred(S):
|
||||
'''Decrement TOS.'''
|
||||
(tos, stack) = S
|
||||
return tos - 1, stack
|
||||
|
||||
|
||||
@inscribe
|
||||
@SimpleFunctionWrapper
|
||||
def pm(stack):
|
||||
'''
|
||||
Plus or minus
|
||||
::
|
||||
|
||||
a b pm
|
||||
-------------
|
||||
a+b a-b
|
||||
|
||||
'''
|
||||
a, (b, stack) = stack
|
||||
p, m, = b + a, b - a
|
||||
return m, (p, stack)
|
||||
|
||||
|
||||
def floor(n):
|
||||
return int(math.floor(n))
|
||||
|
||||
@@ -350,39 +34,6 @@ def id_(stack):
|
||||
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def sharing(stack, expression, dictionary):
|
||||
'''Print redistribution information.'''
|
||||
print("You may convey verbatim copies of the Program's source code as"
|
||||
' you receive it, in any medium, provided that you conspicuously'
|
||||
' and appropriately publish on each copy an appropriate copyright'
|
||||
' notice; keep intact all notices stating that this License and'
|
||||
' any non-permissive terms added in accord with section 7 apply'
|
||||
' to the code; keep intact all notices of the absence of any'
|
||||
' warranty; and give all recipients a copy of this License along'
|
||||
' with the Program.'
|
||||
' You should have received a copy of the GNU General Public License'
|
||||
' along with Thun. If not see <http://www.gnu.org/licenses/>.')
|
||||
return stack, expression, dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def warranty(stack, expression, dictionary):
|
||||
'''Print warranty information.'''
|
||||
print('THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY'
|
||||
' APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE'
|
||||
' COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM'
|
||||
' "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR'
|
||||
' IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES'
|
||||
' OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE'
|
||||
' ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS'
|
||||
' WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE'
|
||||
' COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.')
|
||||
return stack, expression, dictionary
|
||||
|
||||
|
||||
#
|
||||
# § Combinators
|
||||
#
|
||||
@@ -406,194 +57,9 @@ S_swaack = Symbol('swaack')
|
||||
S_times = Symbol('times')
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def i(stack, expression, dictionary):
|
||||
'''
|
||||
The i combinator expects a quoted program on the stack and unpacks it
|
||||
onto the pending expression for evaluation.
|
||||
::
|
||||
|
||||
[Q] i
|
||||
-----------
|
||||
Q
|
||||
|
||||
'''
|
||||
try:
|
||||
quote, stack = stack
|
||||
except ValueError:
|
||||
raise StackUnderflowError('Not enough values on stack.')
|
||||
return stack, concat(quote, expression), dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def x(stack, expression, dictionary):
|
||||
'''
|
||||
::
|
||||
|
||||
x == dup i
|
||||
|
||||
... [Q] x = ... [Q] dup i
|
||||
... [Q] x = ... [Q] [Q] i
|
||||
... [Q] x = ... [Q] Q
|
||||
|
||||
'''
|
||||
quote, _ = stack
|
||||
return stack, concat(quote, expression), dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def b(stack, expression, dictionary):
|
||||
'''
|
||||
::
|
||||
|
||||
b == [i] dip i
|
||||
|
||||
... [P] [Q] b == ... [P] i [Q] i
|
||||
... [P] [Q] b == ... P Q
|
||||
|
||||
'''
|
||||
q, (p, (stack)) = stack
|
||||
return stack, concat(p, concat(q, expression)), dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def ii(stack, expression, dictionary):
|
||||
'''
|
||||
::
|
||||
|
||||
... a [Q] ii
|
||||
------------------
|
||||
... Q a Q
|
||||
|
||||
'''
|
||||
quote, (a, stack) = stack
|
||||
expression = concat(quote, (a, concat(quote, expression)))
|
||||
return stack, expression, dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def dupdip(stack, expression, dictionary):
|
||||
'''
|
||||
::
|
||||
|
||||
[F] dupdip == dup [F] dip
|
||||
|
||||
... a [F] dupdip
|
||||
... a dup [F] dip
|
||||
... a a [F] dip
|
||||
... a F a
|
||||
|
||||
'''
|
||||
F, stack = stack
|
||||
a = stack[0]
|
||||
return stack, concat(F, (a, expression)), dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def infra(stack, expression, dictionary):
|
||||
'''
|
||||
Accept a quoted program and a list on the stack and run the program
|
||||
with the list as its stack. Does not affect the rest of the stack.
|
||||
::
|
||||
|
||||
... [a b c] [Q] . infra
|
||||
-----------------------------
|
||||
c b a . Q [...] swaack
|
||||
|
||||
'''
|
||||
(quote, (aggregate, stack)) = stack
|
||||
return aggregate, concat(quote, (stack, (S_swaack, expression))), dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def genrec(stack, expression, dictionary):
|
||||
'''
|
||||
General Recursion Combinator.
|
||||
::
|
||||
|
||||
[if] [then] [rec1] [rec2] genrec
|
||||
---------------------------------------------------------------------
|
||||
[if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
|
||||
|
||||
From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
|
||||
"The genrec combinator takes four program parameters in addition to
|
||||
whatever data parameters it needs. Fourth from the top is an if-part,
|
||||
followed by a then-part. If the if-part yields true, then the then-part
|
||||
is executed and the combinator terminates. The other two parameters are
|
||||
the rec1-part and the rec2-part. If the if-part yields false, the
|
||||
rec1-part is executed. Following that the four program parameters and
|
||||
the combinator are again pushed onto the stack bundled up in a quoted
|
||||
form. Then the rec2-part is executed, where it will find the bundled
|
||||
form. Typically it will then execute the bundled form, either with i or
|
||||
with app2, or some other combinator."
|
||||
|
||||
The way to design one of these is to fix your base case [then] and the
|
||||
test [if], and then treat rec1 and rec2 as an else-part "sandwiching"
|
||||
a quotation of the whole function.
|
||||
|
||||
For example, given a (general recursive) function 'F':
|
||||
::
|
||||
|
||||
F == [I] [T] [R1] [R2] genrec
|
||||
|
||||
If the [I] if-part fails you must derive R1 and R2 from:
|
||||
::
|
||||
|
||||
... R1 [F] R2
|
||||
|
||||
Just set the stack arguments in front, and figure out what R1 and R2
|
||||
have to do to apply the quoted [F] in the proper way. In effect, the
|
||||
genrec combinator turns into an ifte combinator with a quoted copy of
|
||||
the original definition in the else-part:
|
||||
::
|
||||
|
||||
F == [I] [T] [R1] [R2] genrec
|
||||
== [I] [T] [R1 [F] R2] ifte
|
||||
|
||||
Primitive recursive functions are those where R2 == i.
|
||||
::
|
||||
|
||||
P == [I] [T] [R] tailrec
|
||||
== [I] [T] [R [P] i] ifte
|
||||
== [I] [T] [R P] ifte
|
||||
|
||||
'''
|
||||
(rec2, (rec1, stack)) = stack
|
||||
(then, (if_, _)) = stack
|
||||
F = (if_, (then, (rec1, (rec2, (S_genrec, ())))))
|
||||
else_ = concat(rec1, (F, rec2))
|
||||
return (else_, stack), (S_ifte, expression), dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
@FunctionWrapper
|
||||
def map_(S, expression, dictionary):
|
||||
'''
|
||||
Run the quoted program on TOS on the items in the list under it, push a
|
||||
new list with the results in place of the program and original list.
|
||||
'''
|
||||
# (quote, (aggregate, stack)) = S
|
||||
# results = list_to_stack([
|
||||
# joy((term, stack), quote, dictionary)[0][0]
|
||||
# for term in iter_stack(aggregate)
|
||||
# ])
|
||||
# return (results, stack), expression, dictionary
|
||||
(quote, (aggregate, stack)) = S
|
||||
if not aggregate:
|
||||
return (aggregate, stack), expression, dictionary
|
||||
batch = ()
|
||||
for term in iter_stack(aggregate):
|
||||
s = term, stack
|
||||
batch = (s, (quote, (S_infra, (S_first, batch))))
|
||||
stack = (batch, ((), stack))
|
||||
return stack, (S_infra, expression), dictionary
|
||||
|
||||
|
||||
@inscribe
|
||||
|
||||
Reference in New Issue
Block a user