少し間接的な答えを2つ挙げます。
まず、次のコードについて考えてみます。
module Lambda where
derivApprox f h x = ( (f (x + h)) - (f x) ) / h
これをコンパイルするために、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
乱雑な注釈と冗長性を見渡すと、コンパイラーがすべてをラムダ式に変換したことがわかるはずです。これは、おそらく手動で行う必要がないことを示していると見なすことができます。
逆に、ラムダが必要になる可能性がある状況を考えてみましょう。関数のリストを作成するためにfoldを使用する関数は次のとおりです。
composeAll :: [a -> a] -> a -> a
composeAll = foldr (.) id
あれは何でしょう?ラムダは見えません!実際、逆の方向にも進むことができます。
composeAll' :: [a -> a] -> a -> a
composeAll' xs x = foldr (\f g x -> f (g x)) id xs x
これはラムダでいっぱいであるだけでなく、main関数に対して2つの引数を取り、さらにfoldr
それらすべてに適用されます。foldr
、、のタイプを上記と比較してください(a -> b -> b) -> b -> [a] -> b
。どうやらそれは3つの引数を取るようですが、上記では4つに適用しました!アキュムレータ関数が2つの引数を取ることは言うまでもありませんが、ここでは3つの引数ラムダがあります。もちろん、秘訣は、両方が単一の引数を取る関数を返すことです。ラムダをジャグリングするのではなく、その場でその引数を適用しているだけです。
これらすべてが、うまくいけば、2つの形式が同等であることをあなたに確信させました。誰が違いを見分けることができるので、ラムダフォームは決して必要ではないか、おそらく常に必要です。