Haskell 理解函数类型
在试图理解Haskell如何确定函数类型时,我感到有点困惑。以下是一个例子:Haskell 理解函数类型,haskell,functional-programming,Haskell,Functional Programming,在试图理解Haskell如何确定函数类型时,我感到有点困惑。以下是一个例子: boolFcn x y = x/=3 && y/=4 当我检查上述函数的类型时,它会给出结果: (Num a1, Num a, Eq a1, Eq a) => a -> a1 -> Bool 下面是另一个例子: triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ] 我脑子里出现
boolFcn x y = x/=3 && y/=4
当我检查上述函数的类型时,它会给出结果:
(Num a1, Num a, Eq a1, Eq a) => a -> a1 -> Bool
下面是另一个例子:
triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ]
我脑子里出现了几个问题,我自己很难解决这些问题:
a,a1
文字组成,而三角形的类型由t,t1
文字组成?a
和t
之间有什么区别吗(数值a,等式a)=>a->a->Bool
a
和a1
具有相同的类型类,那么为什么我不能简单地使用一个a
来编写它们呢?当我检查函数的类型时:
let sumthis x y = if x > y then x+y else x-y
我得到一个结果:
(Ord a, Num a) => a -> a -> a
为什么它不会导致:
(Ord a, Num a, Ord a1, Num a1) => a -> a1 -> a
如果这个问题很琐碎,我很抱歉,不过我很乐意听到关于这个问题的任何解释/提示
a
和t
在这些示例中基本相同。这种差异只是类型推断算法的一个副作用boolFcn
中,(Num a,Eq a)=>a->a->Bool
不够一般,因为前两个参数不需要是相同的类型。考虑下面的调用:
boolFcn(4::Int)(4::Double)
这是有效的,因为Int
和Double
都是Num
和Eq
类型类的成员,但它们显然不是同一类型。在您的sumthis
示例中,x
和y
必须是相同的类型,因为它们被用作需要相同类型参数的函数的输入
我们可以通过检查:t(+)
,它返回(+)::numa=>a->a->a
。由于+
的参数必须是相同的类型,x
和y
必须是相同的类型,因此sumthis
必须需要相同类型的参数。所以
sumthis(4::Int)(4::Double)
这是无效的首先,类型中的变量名并不重要。它们是任意命名的,但给定类型的事物将是相同的。例如,
a->b->b=/=a->b->a
,但a->b==c->d
(只要它们不显示在同一类型签名中!)。typechecker动态地为类型变量提供多态值名称,因此不必担心命名方案中的细微差异:它们并不重要。它们只是变量
至于typechecker如何实际确定表达式的类型,让我们看一下第一个示例:
(Num a1, Num a, Eq a1, Eq a) => a -> a1 -> Bool
boolFcn x y = x/=3 && y/=4
首先,类型检查器看到x/=3
。这意味着x
必须是Eq
,因为(/=)
是Eq
类型的一部分,而且,它必须是Num
,因为3
在编译期间被解释为多态Num
类型。同样的事情也发生在y/=4
上,但是y
和x
除了使用(&&&)
之外,没有交互作用。这说明x
和y
不需要是相同的类型,因此标题中的类型变量不同。最后,(&&&
返回一个Bool
,这就是函数返回的结果
你的第二个例子是有点棘手,因为一些语法糖
(Num t2, Num t1, Num t, Enum t2, Enum t1, Enum t) => [(t, t1, t2)]
triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ]
a
、b
和c
现在需要具有相同的类型,因此签名将更改为三角形::(Num t,Enum t)=>[[t]]
如果它们不是相同的类型,为什么不坚持使用(Num a,Eq a,Num b,Eq b)=>a->b->Bool?为什么有时有t1,有时有a1,有时只有b?@Niemand,我不能回答这个问题,但这并不重要。如果您给出自己的类型签名,您可以随意命名类型变量(只要它们以小写字母开头)。如果你不给出自己的类型签名,编译器会编造一些名称,它并不在乎你是否喜欢它们。@Niemand我认为通常的惯例似乎是使用a
和a1
来表示属于同一类型类的“相关”类型,比如在你的boolFcn
,以及a
和b
“无关的类型,如Int
和String
。至于为什么有时是a->a1
,有时是t->t1
,我真的不知道。@Niemand你可能真的想提出一个新问题,特别是关于GHC的类型推断如何选择它的类型变量,因为我在谷歌上找不到太多。@JeffBurka Burka按照你的建议-。不过,谢谢你的重播,这里有一张投票给你:)。
(Num t2, Num t1, Num t, Enum t2, Enum t1, Enum t) => [(t, t1, t2)]
triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ]
triangles = [ [a,b,c] | c <- [1..10], b <- [1..10], a <- [1..10] ]