我正在阅读Understanding Computation的lambda演算部分(第4章)。这段代码尝试在Ruby中使用lambda演算构建MOD
:
MOD = -> m { -> n { CONTROL_IF[
IS_LESS_OR_EQUAL[n][m]
][
MOD[SUBTRACT[m][n]][n]
][
m
]
}}
CONTROL_IF = -> b { b }
IS_LESS_OR_EQUAL = -> m { -> n { IS_ZERO[SUBTRACT[m][n]] }}
IS_ZERO = -> n { n[-> x { B_FALSE }][B_TRUE] }
#Full code would listed below
irb失败并打印SystemStackError: stack level too deep
输入to_integer(MOD[THREE][TWO])
根据这本书,MOD
不起作用,因为它无法实现对Ruby if-else
控制逻辑的惰性求值,并继续以递归方式调用自身。
修改后它可以工作:
#working one
MOD = -> m { -> n { CONTROL_IF[
IS_LESS_OR_EQUAL[n][m]
][
-> x { MOD[SUBTRACT[m][n]][n][x]}
][
m
]
}}
据说-> x { ...[x]}
延迟了MOD
的递归调用,但是我没有得到它。
此外,我在SICP中发生过类似的练习(1.6):
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
作为用户定义的过程,sqrt-iter
会进入无限递归,因为每次都会将(sqrt-iter (improve guess x) x)
作为过程new-if
的参数进行评估。
所以现在我明白实施IF-ELSE
作为一个程序的关键点是懒惰的评价,我的问题是:
MOD
可以正常工作? new-if
( -> x { ...[x]}
),以便延迟递归调用吗? Ruby的完整代码:
ZERO = -> proc { -> x { x } }
ONE = -> proc { -> x { proc[x] } }
TWO = -> proc { -> x { proc[proc[x]] } }
THREE = -> proc { -> x { proc[proc[proc[x]]] } }
FOUR = -> proc { -> x { proc[proc[proc[proc[x]]]] } }
FIVE = -> proc { -> x { proc[proc[proc[proc[proc[x]]]]] } }
def to_integer(proc)
proc[-> n { n + 1 }][0]
end
CONTROL_IF = -> b { b }
B_TRUE = -> x { -> y { x }}
B_FALSE = -> x { -> y { y }}
IS_ZERO = -> n { n[-> x { B_FALSE }][B_TRUE] }
IS_LESS_OR_EQUAL = -> m { -> n { IS_ZERO[SUBTRACT[m][n]] }}
ADD = -> m { -> n { n[INCREMENT][m] } }
SUBTRACT = -> m { -> n { n[DECREMENT][m] } }
PAIR = -> x { -> y { -> f { f[x][y] } } }
LEFT = -> p { p[-> x { -> y { x } } ] }
RIGHT = -> p { p[-> x { -> y { y } } ] }
INCREMENT = -> n { -> p { -> x { p[n[p][x]] } } }
SLIDE = -> p { PAIR[RIGHT[p]][INCREMENT[RIGHT[p]]] }
DECREMENT = -> n { LEFT[n[SLIDE][PAIR[ZERO][ZERO]]] }
=begin
#failed one
MOD = -> m { -> n { CONTROL_IF[
IS_LESS_OR_EQUAL[n][m]
][
MOD[SUBTRACT[m][n]][n]
][
m
]
}}
=end
#working one
MOD = -> m { -> n { CONTROL_IF[
IS_LESS_OR_EQUAL[n][m]
][
-> x { MOD[SUBTRACT[m][n]][n][x]}
][
m
]
}}
#to_integer(MOD[THREE][TWO])
答案 0 :(得分:-1)
我对Ruby语法并不熟悉,但似乎你正在放置表达式的匿名函数。匿名函数确实产生了所需的延迟,因为它在调用之前不会对body进行求值。问题是如何调用它以及在何处调用它。介绍这样一个"就地"延迟会导致代码非常混乱。
在Scheme中,您可以制作if
的延迟版本,但语义略有不同:
(define (new-if test consequent alternative)
(cond (test (consequent))
(else alternative)))
> (new-if (= (+ 1 2) 3)
(lambda () (display "Yay"))
(lambda () (display "Nei")))
Yay
因此,结果和替代需要作为匿名函数传递。请注意,此版本仍使用特殊格式cond
。如果你想要一直到基础知识并通过lambda函数定义if
,并使用一种具有应用评估顺序的语言(即严格像Scheme),你就要设置一个非常困难的任务来控制表达式被延迟,而不是表达式。