Mat*_*ick 8 scheme closures haskell higher-order-functions
我是Haskell的新手,也是函数式编程的新手.在其他(除了Haskell)语言中,lambda表单通常非常有用.
例如,在Scheme中:
(define (deriv-approx f)
(lambda (h x)
(/ (- (f (+ x h)
(f x)
h)))
Run Code Online (Sandbox Code Playgroud)
将创建一个闭包(在函数f上)以逼近导数(值x,间隔为h).但是,由于部分应用,在Haskell中似乎不需要使用lambda形式:
deriv-approx f h x = ( (f (x + h)) - (f x) ) / h
Run Code Online (Sandbox Code Playgroud)
在Haskell中需要lambda形式的一些例子是什么?
编辑:用'lambda form'替换'closure'
C. *_*ann 12
我将给出两个稍微间接的答案.
首先,请考虑以下代码:
module Lambda where
derivApprox f h x = ( (f (x + h)) - (f x) ) / h
Run Code Online (Sandbox Code Playgroud)
我已经编译了这个,同时告诉GHC转储一个中间表示,它大致是用作编译过程一部分的Haskell的简化版本,以获得这个:
Lambda.derivApprox
:: forall a. GHC.Real.Fractional a => (a -> a) -> a -> a -> a
[LclIdX]
Lambda.derivApprox =
\ (@ a) ($dFractional :: GHC.Real.Fractional a) ->
let {
$dNum :: GHC.Num.Num a
[LclId]
$dNum = GHC.Real.$p1Fractional @ a $dFractional } in
\ (f :: a -> a) (h :: a) (x :: a) ->
GHC.Real./
@ a
$dFractional
(GHC.Num.- @ a $dNum (f (GHC.Num.+ @ a $dNum x h)) (f x))
h
Run Code Online (Sandbox Code Playgroud)
如果你看过凌乱的注释和冗长,你应该能够看到编译器已经将所有内容都转换为lambda表达式.我们可以认为这表明您可能不需要手动执行此操作.
相反,让我们考虑一下你可能需要lambdas的情况.这是一个使用折叠来组成函数列表的函数:
composeAll :: [a -> a] -> a -> a
composeAll = foldr (.) id
Run Code Online (Sandbox Code Playgroud)
那是什么?看来不是lambda!事实上,我们也可以采取其他方式:
composeAll' :: [a -> a] -> a -> a
composeAll' xs x = foldr (\f g x -> f (g x)) id xs x
Run Code Online (Sandbox Code Playgroud)
这不仅充满了lambdas,它还对主函数提出了两个论点,而且还适用foldr于所有这些参数.比较上面的类型foldr,(a -> b -> b) -> b -> [a] -> b以及 显然它需要三个参数,但上面我们已经应用了四个!更不用说累加器函数有两个参数,但我们在这里有三个参数lambda.当然,诀窍在于两者都返回一个带有单个参数的函数; 我们只是在现场应用这个论点,而不是在周围玩弄lambdas.
希望所有这些都使你相信这两种形式是等价的.Lambda表格永远不是必需的,或者可能总是必要的,因为谁可以说出差异?
两者之间没有语义差异
f x y z w = ...
Run Code Online (Sandbox Code Playgroud)
和
f x y = \z w -> ...
Run Code Online (Sandbox Code Playgroud)
表达式样式(显式lambdas)和声明样式之间的主要区别是语法风格.重要的一种情况是你想要使用一个where条款:
f x y = \z w -> ...
where ... -- x and y are in scope, z and w are not
Run Code Online (Sandbox Code Playgroud)
通过用命名本地函数或部分应用程序替换它们,可以在不使用显式lambda的情况下编写任何Haskell程序.
另请参阅:声明与表达式样式.