我试图通过编写一些使用它们的简单函数来理解 Haskell 中的lambda 函数(即匿名函数)。
在下面的示例中,我只是尝试接收 3 个参数并使用匿名函数添加三个参数中的两个,然后添加第三个参数。我收到一条错误消息,说我必须先声明一个实例。
specialAdd x y z = (\x y -> x + y) + z
我感谢任何解释为什么我的示例不起作用和/或任何有助于我更好地理解 lambda 函数的解释。
我试图通过编写一些使用它们的简单函数来理解 Haskell 中的lambda 函数(即匿名函数)。
在下面的示例中,我只是尝试接收 3 个参数并使用匿名函数添加三个参数中的两个,然后添加第三个参数。我收到一条错误消息,说我必须先声明一个实例。
specialAdd x y z = (\x y -> x + y) + z
我感谢任何解释为什么我的示例不起作用和/或任何有助于我更好地理解 lambda 函数的解释。
specialAdd x y z = (\x y -> x + y) + z
在此示例中,您尝试做的是向数字添加一个函数,但这是行不通的。看(\x y -> x + y) + z
:它有形式a + b
。为了使这样的表达式起作用,a
零件和b
零件必须是相同类型的数字。
Haskell 是一种不寻常的语言,所以它的错误消息很少是“你不能那样做”的形式。所以这里发生的事情是,Haskell 认为那(\x y -> x + y)
是一个函数,并且由于在表达式中a + b
,b
必须与 的类型相同a
,因此它得出结论 也b
必须是一个函数。Haskell 还允许您定义自己的规则来添加非内置类型;所以它不能只给你一个错误说“你不能添加两个函数”,而是“你没有定义一个允许我添加两个函数的规则”。
以下将做你想要的:
specialAdd x y z = ((\x y -> x + y) x y) + z
在这里,您将函数(\x y -> x + y)
应用于参数x
和y
,然后将结果添加到z
.
练习匿名函数的一个好方法是将它们与高阶函数一起使用,如折叠或映射。
使用地图作为入口点,
地图的基本定义,
map f [] = []
map f (x:xs) = f x : f xs
建立了一个例子,
>>> let list = [0..4]
>>> let f x = x + 1
应用我们获得的地图,
>>> map f list
[1,2,3,4,5]
现在,我们可以省略 f 的声明并使用匿名函数替换它,
>>> map (\x->x+1) list
[1,2,3,4,5]
然后我们推断, map f list == map (\x->x+1) list,因此
f = \x-> x + 1 --- The same as f x = x + 1, but this is the equivalent lambda notation.
然后从一个简单的函数开始,我们将了解如何将其转换为匿名函数,然后了解匿名函数如何依赖于 lambda 抽象。
作为练习,尝试转换 fx = 2*x。
现在更复杂了,一个接受两个参数的匿名函数,
又是一个工作示例,
>>> let add x y = x + y
>>> foldl' add 0 [0..4]
10
可以使用匿名函数重写为,
>>> foldl' (\x y -> x + y) 0 [0..4]
再次使用相等我们推导出 add = \xy -> x + y
此外,在 hakell 中,所有函数都是一个参数的函数,我们可以部分应用它,我们可以将之前的匿名函数重写为, add = \x -> ( \y -> x + y)。
那么诀窍在哪里??因为,我只是将匿名函数的使用展示为高阶函数,并从那开始,展示如何利用它来使用 lambda 表示法重写函数。我的意思是它如何帮助你学习如何写下匿名函数?
仅仅是因为我已经给你(展示给你)一个使用高阶函数的现有框架。
这个框架是一个巨大的机会来适应你这个符号。
从中可以推断出无限范围的运动,例如尝试执行以下操作。
A - Find the corresponding anonymous function ?
1 - let f (x,y) = x + y in map f [(0,1),(2,3),(-1,1)]
2 - let f x y = x * y in foldl' f 1 [1..5]
B - Rewrite all of them using lambda notation into a declarative form (f = \x-> (\y-> ...)
等等 ....
总结一下,
一个函数作为
(F0) f x1 x2 ... xn = {BODY of f}
总是可以重写为,
(F1) f = \x1 x2 ... xn -> {BODY of f}
在哪里
(F2) (\x1 x2 ... xn -> {BODY of f})
F2 形式只是匿名函数,将函数纯粹转换为 lambda 演算形式。F1 是一个声明性的 lambda 表示法(因为我们声明了 f,正如我们定义的那样,将它绑定到匿名 F2)。F0 是 Haskeller 的常用符号。
最后一点重点是我们可以在参数之间加上括号,这会创建一个闭包。这样做意味着可以使用函数参数的子集完全评估函数代码的子集(意味着转换为不再出现自由变量的形式),但这是另一回事。
这是正确的形式:
specialAdd a b c = ((\x y -> x + y) a b) + c
来自Learn You a Haskell 的示例...:
zipWith (\a b -> (a * 30 + 3) / b) [5,4,3,2,1] [1,2,3,4,5]
很好的解释: http: //learnyouahaskell.com/higher-order-functions#lambdas
据我了解,Labmbda/Anonymous 函数可帮助您声明“内联”函数,而无需为其命名。对于“->”之后的表达式,“\”(希腊语的 ASCII,λ)位于变量名之前。例如,
(\x y -> x + y)
是类似于 (+) 的匿名 (lambda) 函数。它接受两个 Num 类型的参数并返回它们的总和:
Prelude> :type (+)
(+) :: Num a => a -> a -> a
Prelude> :type (\x y -> x + y)
(\x y -> x + y) :: Num a => a -> a -> a
您的示例不起作用,因为正如其他人指出的那样,它的右侧使用 lambda 函数 (\xy -> x + y) 作为 (+) 运算符的参数,该运算符是默认定义的仅适用于 Num 类型的参数。lambda 函数的一些美妙之处在于它的“匿名”使用。Vladimir 展示了如何通过从左侧传递变量来在声明中使用 lambda 函数。更“匿名”的用法可能是简单地使用变量调用它,而不给函数命名(因此是匿名的)。例如,
Prelude> (\x y z -> x + y + z) 1 2 3
6
and if you like writing parentheses:
Prelude> (((+).) . (+)) 1 2 3
6
或者在更长的表达式中(如在您的示例声明中),例如,
Prelude> filter (\x -> length x < 3) [[1],[1,2],[1,2,3]]
[[1],[1,2]]
您正试图将其用作不正确(+)
的东西。(Num a) => (a -> a -> a) -> a -> ??
(+)
在类中定义Num
并且 (a -> a -> a) 不是该类的实例。
你到底想达到什么目的?