在Haskell中,当我们谈论类型声明时。
我见过->
和=>
。
作为一个例子:我可以进行自己的类型声明。
addMe :: Int -> Int -> Int
addMe x y = x + y
它很好用。
但是,如果我们看看:t sqrt
,我们会得到:
sqrt :: Floating a => a -> a
什么时候使用=>
,什么时候使用->
?
什么时候使用“胖箭头”,什么时候使用“瘦箭头”?
答案 0 :(得分:10)
->
用于显式功能。即如果f
可以用f x
形式的表达式编写,则签名中必须带有以下箭头之一†。具体来说,x
的类型(自变量)必须出现在->
箭头的左侧。
最好至少从一开始就不要将=>
当作功能箭头。‡。从逻辑上讲,它是一个蕴涵箭头:如果 a
是具有属性 Floating a
的类型,则它因此sqrt
的签名是a -> a
。
对于您的addMe
示例(该函数具有两个参数),签名必须始终为x -> y -> z
形式。 可能在其前面可能还有一个q =>
;不会影响功能性,但在允许使用哪种特定类型方面可能有一些说法。通常,如果类型已经固定且具体,则不需要此类约束。就像,您原则上可以对Int
施加约束:
addMe :: Num Int => Int -> Int -> Int
addMe x y = x + y
...但这并不能真正起到任何作用,因为每个人都知道特定类型Int
是Num
类的实例。需要 这样的约束的地方是类型不是固定的而是类型变量(即小写),即函数是否是多态的。你不能只是写
addMe' :: a -> a -> a
addMe' x y = x + y
因为该签名将暗示该函数适用于任何类型a
,但它不适用于所有类型(例如,如何添加两个字符串?也许不是最好的例子,但是您怎么乘两个字符串?)
因此您需要约束
addMe' :: Num a => a -> a -> a
addMe' x y = x + y
这意味着,您不必在乎{em>确切类型a
是什么,但是您确实要求它是数字类型。任何人都可以使用自己的类型MyNumType
使用该函数,但他们需要确保满足Num MyNumType
:然后{em>遵循 addMe'
可以具有签名{{ 1}}。
确保这一点的方法是使用已知为数字的标准类型,例如MyNumType -> MyNumType -> MyNumType
,或者为您的自定义类型和实例声明 Num
class。只有在您确定这是个好主意的情况下,才做后者;通常,您只需要标准的num类型。
† 请注意,箭头在签名中可能不是可见:可以为函数类型使用类型同义词,例如{{ 1}},那么addMe' 5.9 3.7 :: Double
没问题。但是您可以认为typedef本质上只是一个语法包装器。它仍然是相同的类型,并且确实有箭头。
‡ 碰巧逻辑暗示和函数应用可以看作是同一数学概念的两个方面。此外,GHC实际上将类约束实现为函数参数,即所谓的“字典”。但是所有这些都是在幕后发生的,因此,如果它们是隐式函数,那么它们就可以了。在标准的Haskell中,您将永远不会看到type IntEndofunc = Int -> Int
类型的LHS作为该函数所应用于的某些实际参数的类型。
答案 1 :(得分:9)
“细箭头”用于函数类型(t1 -> t2
是具有类型t1
的值并产生类型t2
的函数的类型)。 / p>
“胖箭头”用于类型约束。它将多态函数上的类型约束列表与其余类型分开。因此,给定Floating a => a -> a
,我们具有函数类型a -> a
,该函数的类型可以接受任何类型的参数a
并产生具有相同类型的结果,并带有约束{ {1}},实际上意味着该函数只能与实现Floating a
类型类的类型一起使用。
答案 2 :(得分:0)
->
是函数的构造函数,=>
用于约束,这是Haskell中的一种称为“接口”的类型类。
一个小例子:
sum :: Int -> Int -> Int
sum x y = x + y
该函数仅允许使用Int类型,但是如果您想要一个大int或一个小int,则可能需要Integer,以及如何告诉它同时使用两者?
sum2 :: Integral a => a -> a -> a
sum2 x y = x + y
现在,如果您尝试这样做:
sum2 3 1.5
它会给你一个错误
另外,您可能想知道两个数据是否相等:
equals :: Eq a => a -> a -> Bool
equals x y = x == y
现在是否可以:
3 == 4
没关系
但是,如果您创建:
data T = A | B
equals A B
它将给您:
error:
• No instance for (Eq T) arising from a use of ‘equals’
• In the expression: equals A B
In an equation for ‘it’: it = equals A B
如果您希望它能正常工作,则必须执行以下操作:
data T = A | B deriving Eq
equals A B
False