I've been reading about Haskell and I'm having a hard time understanding how function definitions are handled in this language.
我一直在阅读Haskell,我很难理解函数定义是如何用这种语言来处理的。
Let's say I'm defining a sum
function:
假设我定义一个和函数
let sum x y = x + y
if I query Haskell for its type
如果我查询Haskell的类型。
:t sum
I get
我得到
sum :: (Num a) => a -> a -> a
- What does it mean the
=>
operator? Does it have anything to do with lambda expressions? That's how one signals that what is following the=>
operator is one, in C#. - 什么是=>运算符?它和lambda表达式有关系吗?这就是在c#中,一个信号,即=>运算符是1。
- What does the
a -> a -> a
mean? By eye inspection on a number of different functions I've been trying out, it seems the initiala -> a
are the arguments and the final-> a
is the result of the sum function. If that is right, why not something as(a, a) -> a
, which seems way more intuitive? - a -> a ->是什么意思?通过对我尝试过的一些不同函数的眼睛检查,它似乎是最初的a -> a是参数,而最终的> a是和函数的结果。如果这是正确的,为什么不像(a, a) -> a,看起来更直观?
5 个解决方案
#1
29
0. The Haskell =>
has nothing to do with C#'s =>
. In Haskell an anonymous function is created with
0。Haskell =>与c# 's =>无关。在Haskell中创建了一个匿名函数。
\x -> x * x
Also, don't name the function sum
because such a function already exists in Prelude. Let's call it plus
from now on to avoid confusion.
另外,不要命名函数和,因为这样的函数在序曲中已经存在。从现在起,让我们称它为正,以避免混淆。
1. Anyway, the =>
in Haskell provides a context to the type. For instance:
1。无论如何,Haskell中的=>提供了类型的上下文。例如:
show :: (Show a) => a -> String
Here, The Show a =>
means a
type must be an instance of the type class Show
, which means a
must be convertible to a string. Similarly, (Num a) => a -> a -> a
means the a
type must be an instance of the type class Num, which means a
must be like a number. This puts a constraint on a
so that show
or plus
won't accept some unsupported input, e.g. plus "56" "abc"
. (String is not like a number.)
这里,Show a =>表示类型必须是类型类Show的实例,这意味着必须可转换为字符串。类似地,(Num a) => a -> -> a意味着a类型必须是类Num的实例,这意味着a必须是一个数字。这就给a设置了一个约束,使show或plus不能接受一些不支持的输入,例如加上“56”“abc”。(字符串不像数字。)
A type class is similar to C#'s interface, or more specifically, an interface base-type constraint in generics. See the question Explain Type Classes in Haskell for more info.
类型类类似于c#的接口,更确切地说,是泛型中的接口基类型约束。请参阅Haskell中的问题解释类型类以获得更多信息。
2. a -> a -> a
means a -> (a -> a)
. Therefore, it is actually a unary function that returns another function.
2。a -> a -> a的意思是> (a -> a),因此,它实际上是一个一元函数,返回另一个函数。
plus x = \y -> x + y
This makes partial application (currying) very easy. Partial application is used a lot esp. when using higher order functions. For instance we could use
这使得部分应用程序(currying)非常容易。部分应用程序在使用高阶函数时使用较多。例如,我们可以使用。
map (plus 4) [1,2,3,4]
to add 4 to every element of the list. In fact we could again use partial application to define:
为列表中的每个元素添加4。实际上,我们可以再次使用部分应用程序来定义:
plusFourToList :: Num a => [a] -> [a]
plusFourToList = map (plus 4)
If a function is written in the form (a,b,c,...)->z
by default, we would have to introduce a lot of lambdas:
如果一个函数的形式是(a,b,c,…)->z,那么我们就必须引入大量的lambdas:
plusFourToList = \l -> map(\y -> plus(4,y), l)
#2
10
This is because
这是因为
Every function in Haskell takes a single parameter and returns a single value
Haskell中的每个函数都接受一个参数,并返回一个值。
If a function need to take multiple value, the function would have been a curried function or it have to take a single tuple.
如果一个函数需要取多个值,那么函数就会是一个曲线函数,或者它必须取一个元组。
If we add a parentheses, the function signature becomes:
如果我们添加一个圆括号,函数签名变为:
sum :: (Num a) => a -> (a -> a)
In Haskell, the function signature: A -> B
means a function the "domain" of the function is A
and the "Codomain" of the function is B
; or in a programmer's language, the function takes a parameter of type A
and returns a value of type B
.
在Haskell中,函数签名:A -> B表示函数的“域”为A,函数的“上域”为B;或者在程序员的语言中,函数接受a类型的参数并返回B类型的值。
Therefore, the function definition sum :: Num -> (Num -> Num)
means sum is "a function that takes a parameter of type a
and returns a function of type Num -> Num
".
因此,函数定义sum:: Num -> (Num -> Num)表示sum是“一个函数,它接受a类型的参数并返回一个Num -> Num的函数”。
In effect, this leads to currying/partial function.
实际上,这导致了currying/部分功能。
The concept of currying is essential in functional languages like Haskell, because you will want to do things like:
在像Haskell这样的函数式语言中,currying的概念非常重要,因为您会想要这样做:
map (sum 5) [1, 2, 3, 5, 3, 1, 3, 4] -- note: it is usually better to use (+ 5)
In that code, (sum 5) is a function that takes a single parameter, this function (sum 5) will be called for each item in the list, e.g. ((sum 5) 1) returns 6.
在该代码中,(sum 5)是一个只接受单个参数的函数,该函数(sum 5)将被调用列表中的每一个项,例如((sum 5) 1)返回6。
If sum
had a signature of sum :: (Num, Num) -> Num
, then sum would have to receive both of its parameter at the same time because now sum is a "function that receives a tuple (Num, Num)
and returns a Num".
如果sum有一个sum的签名::(Num, Num) -> Num,那么sum就必须同时接收它的两个参数,因为sum是一个“接收元组(Num, Num)并返回Num的函数”。
Now, the second question, what does Num a => a -> a
means? It's basically a shorthand for saying that each time you see a
in the signature, replace it with Num or with one of its derived class.
现在,第二个问题,Num a => a ->是什么意思?它基本上是一种简写,表示每次在签名中看到a时,用Num或其派生类中的一个替换它。
#3
5
Num a =>
means "in the following, a
shall refer to a type which is an instance of the typeclass Num
" (which is kinda like an interface for number types).
Num a =>的意思是“在下面,a将引用类型的实例,它是类型的实例”(这有点像数字类型的接口)。
The =>
operator separates the "typeclass constraints" from the "body" of the type. It's kind of like the where
operator for generic constraints in C#. You can read it as a logical implication like "if a
is a numeric type then sum
can be used with type a -> a -> a
".
>操作符将“typeclass约束”与类型的“主体”分隔开。这有点像c#中泛型约束的运算符。你可以把它看作一个逻辑暗示,比如“如果a是数字类型,那么sum就可以和a -> a -> a一起使用”。
a -> a -> a
means "a function that takes an a
and returns a function which takes an a
and returns an a
". For this to make sense you need to understand that sum x y
parses as (sum x) y
.
> a -> a的意思是“一个函数,它取a,返回一个函数,它取a并返回a”。为了便于理解,你需要理解x y解析为(和x) y。
In other words: you first call sum
with the argument x
. You then get back a new function of type a -> a
. You then call that function with the argument y
and now you get back a function of type a
, where a
is the type of x
and y
and must be an instance of the Num
typeclass.
换句话说:你第一次调用和参数x,然后返回一个新的函数的类型- >,然后调用函数的参数y现在你返回类型的函数,一个是x和y的类型,必须Num typeclass的实例。
If you want sum
to have type Num a => (a,a) -> a
, you can define it as sum (x,y) = x+y
. In this case you have a function which takes a tuple containing two a
s and returns an a
(where a
is again an instance of the Num
typeclass).
如果你想让sum有类型Num a => (a,a) -> a,你可以把它定义为sum (x,y) = x+y。在本例中,您有一个函数,该函数接受包含两个as的元组并返回一个a(其中a再次是Num typeclass的实例)。
However the "curry style" (functions returning functions to simulate multiple parameters) is much more often used than the tuple style because it allows you to easily partially apply functions. Example map (sum 5) [1,2,3]
. If you had defined sum
with a tuple, you'd have to do map (\y -> sum 5 y) [1,2,3]
.
然而,“curry style”(函数返回函数来模拟多个参数)比tuple风格更常用,因为它允许您轻松地部分地应用函数。示例map (sum 5)[1,2,3]。如果你用一个元组来定义和,你需要做映射(\y ->和5 y)[1,2,3]。
#4
4
it is a -> a -> a
rather than (a, a) -> a
because of currying. Fun fact: Currying was (re)invented by Haskell Curry! Basically it means if you supply one one argument you'll get back another function of type a -> a
, a partial application of sum.
它是a -> a ->,而不是(a, a) -> - a,因为它是currying。有趣的事实:Currying是由Haskell Curry发明的!基本上,这意味着如果你提供一个参数你就会得到另一个a -> a的函数,一个和的局部应用。
#5
4
The Haskell documentation isn't too clear about it, but (Num a) => means that the function works for all cases where a is a Num or derives from it (therefore is a number).
Haskell的文档并不太清楚,但是(Num a) =>意味着该函数适用于所有a为Num的情况,或者来自于它(因此是一个数字)。
Also see: http://www.cse.unsw.edu.au/~en1000/haskell/inbuilt.html
还看到:http://www.cse.unsw.edu.au/ ~ en1000 / haskell / inbuilt.html
#1
29
0. The Haskell =>
has nothing to do with C#'s =>
. In Haskell an anonymous function is created with
0。Haskell =>与c# 's =>无关。在Haskell中创建了一个匿名函数。
\x -> x * x
Also, don't name the function sum
because such a function already exists in Prelude. Let's call it plus
from now on to avoid confusion.
另外,不要命名函数和,因为这样的函数在序曲中已经存在。从现在起,让我们称它为正,以避免混淆。
1. Anyway, the =>
in Haskell provides a context to the type. For instance:
1。无论如何,Haskell中的=>提供了类型的上下文。例如:
show :: (Show a) => a -> String
Here, The Show a =>
means a
type must be an instance of the type class Show
, which means a
must be convertible to a string. Similarly, (Num a) => a -> a -> a
means the a
type must be an instance of the type class Num, which means a
must be like a number. This puts a constraint on a
so that show
or plus
won't accept some unsupported input, e.g. plus "56" "abc"
. (String is not like a number.)
这里,Show a =>表示类型必须是类型类Show的实例,这意味着必须可转换为字符串。类似地,(Num a) => a -> -> a意味着a类型必须是类Num的实例,这意味着a必须是一个数字。这就给a设置了一个约束,使show或plus不能接受一些不支持的输入,例如加上“56”“abc”。(字符串不像数字。)
A type class is similar to C#'s interface, or more specifically, an interface base-type constraint in generics. See the question Explain Type Classes in Haskell for more info.
类型类类似于c#的接口,更确切地说,是泛型中的接口基类型约束。请参阅Haskell中的问题解释类型类以获得更多信息。
2. a -> a -> a
means a -> (a -> a)
. Therefore, it is actually a unary function that returns another function.
2。a -> a -> a的意思是> (a -> a),因此,它实际上是一个一元函数,返回另一个函数。
plus x = \y -> x + y
This makes partial application (currying) very easy. Partial application is used a lot esp. when using higher order functions. For instance we could use
这使得部分应用程序(currying)非常容易。部分应用程序在使用高阶函数时使用较多。例如,我们可以使用。
map (plus 4) [1,2,3,4]
to add 4 to every element of the list. In fact we could again use partial application to define:
为列表中的每个元素添加4。实际上,我们可以再次使用部分应用程序来定义:
plusFourToList :: Num a => [a] -> [a]
plusFourToList = map (plus 4)
If a function is written in the form (a,b,c,...)->z
by default, we would have to introduce a lot of lambdas:
如果一个函数的形式是(a,b,c,…)->z,那么我们就必须引入大量的lambdas:
plusFourToList = \l -> map(\y -> plus(4,y), l)
#2
10
This is because
这是因为
Every function in Haskell takes a single parameter and returns a single value
Haskell中的每个函数都接受一个参数,并返回一个值。
If a function need to take multiple value, the function would have been a curried function or it have to take a single tuple.
如果一个函数需要取多个值,那么函数就会是一个曲线函数,或者它必须取一个元组。
If we add a parentheses, the function signature becomes:
如果我们添加一个圆括号,函数签名变为:
sum :: (Num a) => a -> (a -> a)
In Haskell, the function signature: A -> B
means a function the "domain" of the function is A
and the "Codomain" of the function is B
; or in a programmer's language, the function takes a parameter of type A
and returns a value of type B
.
在Haskell中,函数签名:A -> B表示函数的“域”为A,函数的“上域”为B;或者在程序员的语言中,函数接受a类型的参数并返回B类型的值。
Therefore, the function definition sum :: Num -> (Num -> Num)
means sum is "a function that takes a parameter of type a
and returns a function of type Num -> Num
".
因此,函数定义sum:: Num -> (Num -> Num)表示sum是“一个函数,它接受a类型的参数并返回一个Num -> Num的函数”。
In effect, this leads to currying/partial function.
实际上,这导致了currying/部分功能。
The concept of currying is essential in functional languages like Haskell, because you will want to do things like:
在像Haskell这样的函数式语言中,currying的概念非常重要,因为您会想要这样做:
map (sum 5) [1, 2, 3, 5, 3, 1, 3, 4] -- note: it is usually better to use (+ 5)
In that code, (sum 5) is a function that takes a single parameter, this function (sum 5) will be called for each item in the list, e.g. ((sum 5) 1) returns 6.
在该代码中,(sum 5)是一个只接受单个参数的函数,该函数(sum 5)将被调用列表中的每一个项,例如((sum 5) 1)返回6。
If sum
had a signature of sum :: (Num, Num) -> Num
, then sum would have to receive both of its parameter at the same time because now sum is a "function that receives a tuple (Num, Num)
and returns a Num".
如果sum有一个sum的签名::(Num, Num) -> Num,那么sum就必须同时接收它的两个参数,因为sum是一个“接收元组(Num, Num)并返回Num的函数”。
Now, the second question, what does Num a => a -> a
means? It's basically a shorthand for saying that each time you see a
in the signature, replace it with Num or with one of its derived class.
现在,第二个问题,Num a => a ->是什么意思?它基本上是一种简写,表示每次在签名中看到a时,用Num或其派生类中的一个替换它。
#3
5
Num a =>
means "in the following, a
shall refer to a type which is an instance of the typeclass Num
" (which is kinda like an interface for number types).
Num a =>的意思是“在下面,a将引用类型的实例,它是类型的实例”(这有点像数字类型的接口)。
The =>
operator separates the "typeclass constraints" from the "body" of the type. It's kind of like the where
operator for generic constraints in C#. You can read it as a logical implication like "if a
is a numeric type then sum
can be used with type a -> a -> a
".
>操作符将“typeclass约束”与类型的“主体”分隔开。这有点像c#中泛型约束的运算符。你可以把它看作一个逻辑暗示,比如“如果a是数字类型,那么sum就可以和a -> a -> a一起使用”。
a -> a -> a
means "a function that takes an a
and returns a function which takes an a
and returns an a
". For this to make sense you need to understand that sum x y
parses as (sum x) y
.
> a -> a的意思是“一个函数,它取a,返回一个函数,它取a并返回a”。为了便于理解,你需要理解x y解析为(和x) y。
In other words: you first call sum
with the argument x
. You then get back a new function of type a -> a
. You then call that function with the argument y
and now you get back a function of type a
, where a
is the type of x
and y
and must be an instance of the Num
typeclass.
换句话说:你第一次调用和参数x,然后返回一个新的函数的类型- >,然后调用函数的参数y现在你返回类型的函数,一个是x和y的类型,必须Num typeclass的实例。
If you want sum
to have type Num a => (a,a) -> a
, you can define it as sum (x,y) = x+y
. In this case you have a function which takes a tuple containing two a
s and returns an a
(where a
is again an instance of the Num
typeclass).
如果你想让sum有类型Num a => (a,a) -> a,你可以把它定义为sum (x,y) = x+y。在本例中,您有一个函数,该函数接受包含两个as的元组并返回一个a(其中a再次是Num typeclass的实例)。
However the "curry style" (functions returning functions to simulate multiple parameters) is much more often used than the tuple style because it allows you to easily partially apply functions. Example map (sum 5) [1,2,3]
. If you had defined sum
with a tuple, you'd have to do map (\y -> sum 5 y) [1,2,3]
.
然而,“curry style”(函数返回函数来模拟多个参数)比tuple风格更常用,因为它允许您轻松地部分地应用函数。示例map (sum 5)[1,2,3]。如果你用一个元组来定义和,你需要做映射(\y ->和5 y)[1,2,3]。
#4
4
it is a -> a -> a
rather than (a, a) -> a
because of currying. Fun fact: Currying was (re)invented by Haskell Curry! Basically it means if you supply one one argument you'll get back another function of type a -> a
, a partial application of sum.
它是a -> a ->,而不是(a, a) -> - a,因为它是currying。有趣的事实:Currying是由Haskell Curry发明的!基本上,这意味着如果你提供一个参数你就会得到另一个a -> a的函数,一个和的局部应用。
#5
4
The Haskell documentation isn't too clear about it, but (Num a) => means that the function works for all cases where a is a Num or derives from it (therefore is a number).
Haskell的文档并不太清楚,但是(Num a) =>意味着该函数适用于所有a为Num的情况,或者来自于它(因此是一个数字)。
Also see: http://www.cse.unsw.edu.au/~en1000/haskell/inbuilt.html
还看到:http://www.cse.unsw.edu.au/ ~ en1000 / haskell / inbuilt.html