Я собираюсь дать два слегка косвенных ответа.
Во-первых, рассмотрим следующий код:
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
Если вы посмотрите мимо грязных аннотаций и многословия, вы должны увидеть, что компилятор имеет превратил все в лямбда-выражения .Мы можем считать это признаком того, что вам, вероятно, не нужно делать это вручную.
И наоборот, давайте рассмотрим ситуацию, когда вам могут понадобиться лямбды.Вот функция, которая использует сгиб для составления списка функций:
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
Мало того, что он полон лямбда-выражений, он также принимает два аргумента для главной функции и, более того,применяя foldr
ко всем из них.Сравните тип foldr
, (a -> b -> b) -> b -> [a] -> b
с приведенным выше;очевидно, требуется три аргумента, но выше мы применили его к четырем!Не говоря уже о том, что функция аккумулятора принимает два аргумента, но здесь у нас есть лямбда с тремя аргументами.Хитрость, конечно, в том, что оба возвращают функцию, которая принимает один аргумент;и мы просто применяем этот аргумент на месте, вместо того, чтобы жонглировать лямбдами вокруг.
Все это, надеюсь, убедило вас в том, что эти две формы эквивалентны.Лямбда-формы никогда не нужны или, возможно, всегда необходимы, потому что кто может отличить их?