在arrow do notation中,您可以使用rec关键字编写递归定义。举个例子:
rec
name <- function -< input
input <- otherFunction -< name
这怎么能进行评估呢?它看起来就像是进入了一个无限循环或者别的什么。我知道它的计算结果是循环箭头组合器,但我也不明白它是如何工作的。
编辑: powers示例非常有用。但是,如何使用do表示法来编写呢?我假设你需要使用rec。
发布于 2011-03-23 13:33:10
这点魔法是由于haskells的懒惰而起作用的。正如您可能知道的,Haskell在需要时而不是在定义时计算值。因此,如果您不需要直接或稍后输入该值,则可以使用此方法。
rec
是使用ArrowLoop
的loop
函数实现的。它的定义如下:
class Arrow a => ArrowLoop a where
loop :: a (b,d) (c,d) -> a b c
instance ArrowLoop (->) where
loop f b = let (c,d) = f (b,d) in c
您可以看到:输出只是作为输入进行反馈。它只会被计算一次,因为Haskell只会在需要的时候评估d
。
下面是一个如何直接使用loop
组合器的实际示例。此函数计算其参数的所有幂:
powers = loop $ \(x,l) -> (l,x:map(*x)l)
(你也可以这样写:powers x = fix $ (x :) . map (*x)
)
它是如何工作的?好的,无限的权力列表在l
的论点中。评估结果如下所示:
powers = loop $ \(x,l) -> (l,x:map(*x)l) ==>
powers b = let (c,d) = (\(x,l) -> (l,x:map(*x)l)) (b,d) in c ==>
powers b = let (c,d) = (d,b:map(*b)d) in d ==> -- Now we apply 2 as an argument
powers 2 = let (c,d) = (d,2:map(*2)d) in d ==>
= let (c,(2:d)) = (d,2:map(*2)d) in c ==>
= let (c,(2:4:d)) = ((2:d),2:map(*2)(2:d)) in c ==>
= let (c,(2:4:8:d)) = ((2:4:d),2:map(*2)(2:4:d)) in ==> -- and so on
发布于 2011-03-23 20:46:12
下面是一个真实的例子:
loop f b = let (c,d) = f (b,d) in c
f (b,d) = (drop (d-2) b, length b)
main = print (loop f "Hello World")
这个程序输出"ld“。函数'loop f‘接受一个输入'b’,并创建一个输出'c‘。'f‘正在做的是研究'b’来产生'length b‘,它被返回到循环并绑定到'd’。
在‘循环’中,这个'd=length b‘被输入到'f’中,在丢弃的计算中使用它。
这对于构建不可变的双向链表(也可以是循环的)这样的技巧很有用。它对于遍历一次'b‘也很有用,既可以产生一些解析的'd’(例如长度或最大元素),也可以构建一个依赖于'd‘的新结构'c’。懒惰避免了必须遍历“b”两次。
https://stackoverflow.com/questions/5405850
复制