From f640f437f1f05c89d06bd5735f0cc18a567662af Mon Sep 17 00:00:00 2001 From: Simon Forman Date: Mon, 12 Sep 2022 13:50:40 -0700 Subject: [PATCH] cond --- implementations/Python/joy/library.py | 93 --------------------------- implementations/Python/simplejoy.py | 57 +++++++++++++++- 2 files changed, 56 insertions(+), 94 deletions(-) diff --git a/implementations/Python/joy/library.py b/implementations/Python/joy/library.py index c39c164..2c9d0f9 100644 --- a/implementations/Python/joy/library.py +++ b/implementations/Python/joy/library.py @@ -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): diff --git a/implementations/Python/simplejoy.py b/implementations/Python/simplejoy.py index 5453bba..79c4015 100755 --- a/implementations/Python/simplejoy.py +++ b/implementations/Python/simplejoy.py @@ -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), '•')