This commit is contained in:
Simon Forman 2022-09-12 13:50:40 -07:00
parent 77bd7790f5
commit f640f437f1
2 changed files with 56 additions and 94 deletions

View File

@ -75,99 +75,6 @@ S_times = Symbol('times')
# return (q, (p, stack)), expression, dictionary
@inscribe
@FunctionWrapper
def branch(stack, expression, dictionary):
'''
Use a Boolean value to select one of two quoted programs to run.
::
branch == roll< choice i
::
False [F] [T] branch
--------------------------
F
True [F] [T] branch
-------------------------
T
'''
(then, (else_, (flag, stack))) = stack
return stack, concat(then if flag else else_, expression), dictionary
@inscribe
@FunctionWrapper
def ifte(stack, expression, dictionary):
'''
If-Then-Else Combinator
::
... [if] [then] [else] ifte
---------------------------------------------------
... [[else] [then]] [...] [if] infra select i
... [if] [then] [else] ifte
-------------------------------------------------------
... [else] [then] [...] [if] infra first choice i
Has the effect of grabbing a copy of the stack on which to run the
if-part using infra.
'''
(else_, (then, (if_, stack))) = stack
expression = (S_infra, (S_first, (S_choice, (S_i, expression))))
stack = (if_, (stack, (then, (else_, stack))))
return stack, expression, dictionary
@inscribe
@FunctionWrapper
def cond(stack, expression, dictionary):
'''
This combinator works like a case statement. It expects a single quote
on the stack that must contain zero or more condition quotes and a
default quote. Each condition clause should contain a quoted predicate
followed by the function expression to run if that predicate returns
true. If no predicates return true the default function runs.
It works by rewriting into a chain of nested `ifte` expressions, e.g.::
[[[B0] T0] [[B1] T1] [D]] cond
-----------------------------------------
[B0] [T0] [[B1] [T1] [D] ifte] ifte
'''
conditions, stack = stack
if conditions:
expression = _cond(conditions, expression)
try:
# Attempt to preload the args to first ifte.
(P, (T, (E, expression))) = expression
except ValueError:
# If, for any reason, the argument to cond should happen to contain
# only the default clause then this optimization will fail.
pass
else:
stack = (E, (T, (P, stack)))
return stack, expression, dictionary
def _cond(conditions, expression):
(clause, rest) = conditions
if not rest: # clause is [D]
return clause
P, T = clause
return (P, (T, (_cond(rest, ()), (S_ifte, expression))))
@inscribe
@FunctionWrapper
def dip(stack, expression, dictionary):

View File

@ -2031,6 +2031,56 @@ def ifte(stack, expr, dictionary):
return stack, expr, dictionary
S_cond = Symbol('cond')
@inscribe
def cond(stack, expr, dictionary):
'''
This combinator works like a case statement. It expects a single quote
on the stack that must contain zero or more condition quotes and a
default quote. Each condition clause should contain a quoted predicate
followed by the function expression to run if that predicate returns
true. If no predicates return true the default function runs.
It works by rewriting into a chain of nested `ifte` expressions, e.g.::
[[D]] cond
---------------- (Kind of pointless)
D
[[[IF] THEN] [D]] cond
---------------------------- (with single condition, same as ifte)
[IF] [THEN] [D] ifte
[[[IF] THEN] ...] cond
----------------------------------- (multiple conditions)
[IF] [THEN] [[...] cond] ifte
The middle case isn't actually implemented. It's implied by the
base case and the "multiple conditions" case.
'''
conditions, stack = get_n_items(1, stack)
isnt_stack(conditions)
if not conditions:
raise StackUnderflowError('cond without default clause')
condition_clause, conditions = conditions
isnt_stack(condition_clause)
if not conditions: # This is the default clause, run it.
expr = push_quote(condition_clause, expr)
else:
if_, then = get_n_items(1, condition_clause)
isnt_stack(if_)
else_ = (conditions, (S_cond, ()))
stack = (else_, (then, (if_, stack)))
expr = push_quote((S_ifte, ()), expr)
return stack, expr, dictionary
if __name__ == '__main__':
import sys
@ -2041,5 +2091,10 @@ if __name__ == '__main__':
## stack = J(dictionary=dictionary)
## except SystemExit:
## pass
stack, _ = run("5 10 [>][++][*]ifte", (), dictionary)
jcode = "5 10 [>][++][*]ifte"
jcode = '1 2 [[+]] cond'
jcode = '1 2 [[[>] -] [[<] +] [*]] cond'
jcode = '2 1 [[[>] -] [[<] +] [*]] cond'
jcode = '3 3 [[[>] -] [[<] +] [*]] cond'
stack, _ = run(jcode, (), dictionary)
print(stack_to_string(stack), '')