在箭头符号中,可以使用rec关键字来编写递归定义。例如:Haskell rec关键字如何工作?
rec
name <- function -< input
input <- otherFunction -< name
这怎么能评估?它似乎会进入一个无限循环或什么东西。我知道它评估到循环箭头组合器,但我不明白这是如何工作。
编辑:这个权力的例子真的很有帮助。尽管如此,你会如何写这个符号?我假设你需要使用rec。
在箭头符号中,可以使用rec关键字来编写递归定义。例如:Haskell rec关键字如何工作?
rec
name <- function -< input
input <- otherFunction -< name
这怎么能评估?它似乎会进入一个无限循环或什么东西。我知道它评估到循环箭头组合器,但我不明白这是如何工作。
编辑:这个权力的例子真的很有帮助。尽管如此,你会如何写这个符号?我假设你需要使用rec。
由于haskells懒惰,这一点神奇的作品。正如您可能知道的那样,Haskell在需要时评估一个值,而不是在定义时评估。因此,如果您不需要直接输入的值,或者稍后输入值,则此功能可以正常工作。
rec
使用loop
函数ArrowLoop
实现。这是其次的定义:
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 13:58:53
诀窍是,Haskell不会评估未使用的参数。只是控制流程没有必要与您想象的一样。 – fuz 2011-03-23 15:20:42
'f(b,_)'在计算输出'd'时只能使用输入'b'。 'f'在构建'c'时可以同时使用'b'和'd',只要它不强迫评估'd'使其挂起。你可以这样想:当'c'被强制时,'d'从'b'计算,然后'c'从'b'和'd'计算。 – 2011-03-23 20:50:44
这里是一个真正的十岁上下的例子:
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'来产生'长度b',这个长度被返回到循环并绑定到'd'。
在'循环'中,'d =长度b'被输入到'f'中,并在drop中用于计算。
这对于像构建一个不可变的双向链表(这也可能是循环)这样的技巧很有用。它也可用于遍历'b',既产生一些分析'd'(如长度或最大元素),又构建一个依赖于'd'的新结构'c'。懒惰避免了必须遍历'b'两次。
[案例](http://www.haskell.org/haskellwiki/Keywords#rec)之前有人没有听说过“rec”。 – 2012-10-19 13:00:50