ArrowLoop
的函数实例包含
loop :: ((b,d) -> (c,d)) -> (b -> c)
loop f b = let (c,d) = f (b,d) in c
首先我的签名有问题:我们怎样才能从b -> c
获得(b,d) -> (c,d)
?我的意思是,结果元组中的c
可能取决于输入的两个元素,如何“切断”d
的影响?
其次我不知道let
在这里是如何运作的。不包含(c,d) = f (b,d)
d
的循环定义? d
来自哪里?说实话,我很惊讶这是有效的语法,因为看起来我们会重新定义d
。
我的意思是在数学中这会有点意义,例如: f可能是一个复杂的函数,但我只提供实部b,我需要选择虚部d,当它评估f(b,d)时它不会改变,这将使它成为某种固定点。但是,如果这个类比成立,let
表达式必须以某种方式“搜索”d的固定点(并且可能有多个)。这对我来说看起来很神奇。或者我觉得太复杂了?
答案 0 :(得分:14)
这与fix
的标准定义的工作方式相同:
fix f = let x = f x in x
,即它在exact same way fix
does中找到了一个固定点:递归。
例如,作为一个简单的例子,考虑loop (\((),xs) -> (xs, 1:xs)) ()
。这就像fix (\xs -> 1:xs)
;我们忽略输入,并使用d
输出(此处为xs
)作为主输出。 loop
所具有的元组中的额外元素只是包含输入参数和输出值,因为箭头不能进行currying。考虑一下如何用fix
定义阶乘函数 - 你最终会使用currying,但是当使用箭头时,你会使用loop
给你的额外参数和输出。
基本上,loop
绑定一个结,让箭头访问自身的辅助输出,就像fix
绑定一个结,让函数访问自己的输出作为输入。
答案 1 :(得分:6)
“搜索固定点”完全这是做什么的。这是Haskell在行动中的懒惰。请参阅Wikipedia。