Haskell "fix" 关键字在声明递归 lambda 函数时失败
Haskell "fix" keyword failed on declaring a recursive lambda function
似乎一个函数应该有一个递归的名字(以便调用自己),那么lambda函数是如何递归的?
我搜索了维基百科,它说这可以由 "Y-combinator" 完成。我没有太多的数学理论背景,它只是告诉我 "Y-combinator" 是由 Haskell 自己发现的。在Haskell语言中调用"fix"关键字,我试过:
Prelude> let fact = fix (\f n -> if n == 0 then 1 else n * (f (n-1)))
<interactive>:17:12: Not in scope: ‘fix’
似乎失败了,但是如何使用 "fix" 关键字来达到我预期的效果?
fix
不是关键字,是Data.Function
模块中定义的函数。因此,要使用它,您必须导入该模块。
import Data.Function
或在 GHCi 中:
:m Data.Function
fix
定义为:
fix :: (a -> a) -> a
fix f = let x = f x in x
因此它扩展为 f (f (f (f ...)))
即输入函数 f
对某些参数 x
.
的无限嵌套应用序列
您可以给您的 lambda 函数一个顶级定义,例如
factF f n = if n == 0 then 1 else n * f (n - 1)
或等同于:
factF :: (Int -> Int) -> (Int -> Int)
factF f = \n -> if n == 0 then 1 else n * f (n - 1)
你可以把这个函数提供给fix
得到一个函数(Int -> Int)
即
fact :: (Int -> Int)
fact = fix factF
如果你展开这个定义你会得到
factF (factF (factF (factF ...)))
=> \n -> if n == 0 then 1 else (factF (factF (factF ...)))
由于懒惰,factF
的重复应用仅在 n /= 0
时才被评估,因此应用于 0
的上述函数将立即评估为 1。
您可以在这个扩展中看到 factF
作为参数提供给它自己,然后它应用于较小版本的 n
。由于 factN
与您的 lambda 函数相同,因此那里发生了同样的事情 - lambda 内部的参数 f
是 lambda 本身,然后可以递归调用它。
似乎一个函数应该有一个递归的名字(以便调用自己),那么lambda函数是如何递归的?
我搜索了维基百科,它说这可以由 "Y-combinator" 完成。我没有太多的数学理论背景,它只是告诉我 "Y-combinator" 是由 Haskell 自己发现的。在Haskell语言中调用"fix"关键字,我试过:
Prelude> let fact = fix (\f n -> if n == 0 then 1 else n * (f (n-1)))
<interactive>:17:12: Not in scope: ‘fix’
似乎失败了,但是如何使用 "fix" 关键字来达到我预期的效果?
fix
不是关键字,是Data.Function
模块中定义的函数。因此,要使用它,您必须导入该模块。
import Data.Function
或在 GHCi 中:
:m Data.Function
fix
定义为:
fix :: (a -> a) -> a
fix f = let x = f x in x
因此它扩展为 f (f (f (f ...)))
即输入函数 f
对某些参数 x
.
您可以给您的 lambda 函数一个顶级定义,例如
factF f n = if n == 0 then 1 else n * f (n - 1)
或等同于:
factF :: (Int -> Int) -> (Int -> Int)
factF f = \n -> if n == 0 then 1 else n * f (n - 1)
你可以把这个函数提供给fix
得到一个函数(Int -> Int)
即
fact :: (Int -> Int)
fact = fix factF
如果你展开这个定义你会得到
factF (factF (factF (factF ...)))
=> \n -> if n == 0 then 1 else (factF (factF (factF ...)))
由于懒惰,factF
的重复应用仅在 n /= 0
时才被评估,因此应用于 0
的上述函数将立即评估为 1。
您可以在这个扩展中看到 factF
作为参数提供给它自己,然后它应用于较小版本的 n
。由于 factN
与您的 lambda 函数相同,因此那里发生了同样的事情 - lambda 内部的参数 f
是 lambda 本身,然后可以递归调用它。