声明lambda函数时出错:首先声明一个实例

时间:2013-03-27 13:38:26

标签: haskell

我试图通过编写一些使用它们的简单函数来理解Haskell中的 lambda函数(即匿名函数)。

在下面的示例中,我只是尝试接受3个参数,并使用匿名函数添加三个参数中的两个,然后添加第三个参数。 我收到一个错误,说我必须先声明一个实例。

specialAdd x y z = (\x y -> x + y) + z

我感谢任何解释为什么我的例子不起作用和/或任何有助于我更好地理解lambda函数的解释。

5 个答案:

答案 0 :(得分:17)

  

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)应用于参数xy,然后将结果添加到z

答案 1 :(得分:10)

练习匿名函数的一个好方法是使用高阶函数作为折叠或贴图。

使用map作为入口点,

地图的基本定义,

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抽象。

作为练习尝试翻译f x = 2 * x。

现在更复杂,一个带有两个参数的匿名函数,

再一个工作的例子,

>>> let add x y = x + y
>>> foldl' add 0 [0..4]
10

可以使用匿名函数重写,

>>> foldl' (\x y -> x + y) 0 [0..4]  

再次使用相等,我们推断出add = \ x y - > 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的常用符号。

最后一个注意事项,我们可以在参数之间放置括号,这会创建一个闭包。这样做意味着可以使用函数参数的子集完全评估函数代码的子集(意味着转换为不再发生自由变量的形式),但这是另一个故事。

答案 2 :(得分:3)

这是正确的形式:
specialAdd a b c = ((\x y -> x + y) a b) + c

向你学习哈斯克尔的例子......:
zipWith (\a b -> (a * 30 + 3) / b) [5,4,3,2,1] [1,2,3,4,5]

很好的解释: http://learnyouahaskell.com/higher-order-functions#lambdas

答案 3 :(得分:2)

根据我的理解,Labmbda / Anonymous函数可帮助您声明函数“inline”而无需为其命名。 “\”(希腊语的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]]

答案 4 :(得分:1)

您正试图将(+)用作(Num a) => (a -> a -> a) -> a -> ??之类的错误。

(+)在课程Num中定义,(a - &gt; a - &gt; a)不是此课程的实例。

你到底想要达到什么目的?