[英]Difference in Function typing in Haskell
I've been playing around with basic functions in Haskell, and am a little confused with the difference between the following type declarations for the function f
我一直在玩Haskell中的基本函数,并且对函数f
的以下类型声明之间的区别有点困惑
f :: Integer -> Integer
versus 与
f :: Integral n => n -> n
So far, I've treated both of these as identical, but I'm sure this isn't true. 到目前为止,我已将这两者视为相同,但我确信这不是真的。 What is the difference? 有什么区别?
Edit: As a response to the first answer, I wanna propose a similar example which more is along the lines of the question I hold. 编辑:作为对第一个答案的回答,我想提出一个类似的例子,更多的是我所持的问题。
Consider the following declarations 请考虑以下声明
f :: Num n => n -> n
or 要么
f :: Num -> Num
What functionality does each offer? 每个提供什么功能?
Let's rename: 我们重命名:
f :: Integer -> Integer
g :: (Integral n) => n -> n
I like to follow a fairly common practice of adding parentheses to the constraint section of the signature. 我喜欢遵循一种相当常见的做法,即在签名的约束部分添加括号。 It helps it stand out as different. 它有助于它脱颖而出。
f :: Integer -> Integer
is simple, it takes an integer and returns another integer. f :: Integer -> Integer
很简单,它取一个整数并返回另一个整数。
As for g :: (Integral n) => n -> n
: Integral
is not a type itself, rather it's more like a predicate. 至于g :: (Integral n) => n -> n
: Integral
本身不是一个类型,而是更像谓词。 Some types are Integral
, others aren't. 有些类型是Integral
,有些类型不是。 For example, Int
is an Integral
type, Double
is not. 例如, Int
是Integral
类型, Double
不是。
Here n
is a type variable , and it can refer to any type. 这里n
是一个类型变量 ,它可以引用任何类型。 (Integral n)
is a constraint on the type variable, which restricts what types it can refer to. (Integral n)
是对类型变量的约束 ,它限制了它可以引用的类型。 So you could read it like this: 所以你可以这样读:
g
takes a value of any typen
and returns a value of that same type , provided that it is anIntegral
type.g
取任何类型n
的值并返回相同类型的值,前提是它是一个Integral
类型。
If we examine the Integral
typeclass: 如果我们检查Integral
类型类:
ghci> :info Integral
class (Real a, Enum a) => Integral a where
quot :: a -> a -> a
rem :: a -> a -> a
div :: a -> a -> a
mod :: a -> a -> a
quotRem :: a -> a -> (a, a)
divMod :: a -> a -> (a, a)
toInteger :: a -> Integer
{-# MINIMAL quotRem, toInteger #-}
-- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’
We can see 3 builtin types which are Integral
. 我们可以看到3种内置类型,即Integral
。 Which means that g
simultaneously has three different types, depending on how it is used. 这意味着g
同时具有三种不同的类型,具体取决于它的使用方式。
g :: Word -> Word
g :: Integer -> Integer
g :: Int -> Int
(And if you define another Integral
type in the future, g
will automatically work with that as well) (如果你将来定义另一个Integral
类型, g
也会自动使用它)
The Word -> Word
variant is a good example, since Word
s cannot be negative. Word -> Word
变体是一个很好的例子,因为Word
不能是否定的。 g
, when given a positive machine-sized number, returns another positive machine-sized number, whereas f
could return any integer, including negative ones or gigantic ones. g
,当给出一个正的机器大小的数字时,返回另一个正的机器大小的数字,而f
可以返回任何整数,包括负整数或巨大的整数。
Integral
is a rather specific class. Integral
是一个相当具体的类。 It's easier to see with Num
, which has fewer methods and thus can represent more types: 使用Num
更容易看到, Num
具有更少的方法,因此可以代表更多类型:
h :: (Num a) => a -> a
This is also a generalization of f
, that is, you could use h
where something with f
's type is expected. 这也是f
的推广,也就是说,你可以使用h
来预期带有f
类型的东西。 But h
can also take a complex number, and it would then return a complex number. 但是h
也可以采用复数,然后返回一个复数。
The key with signatures like g
's and h
's is that they work on multiple types, as long as the return type is the same as the input type. 具有g
和h
等签名的密钥是它们可以处理多种类型,只要返回类型与输入类型相同即可。
According to this link the standard instances of the Integral
type class are Integer
and Int
. 根据此链接 , Integral
类型类的标准实例是Integer
和Int
。 Integer
is a primitive type, and it acts like an unbounded mathematical integer. Integer
是一种原始类型,它的作用类似于无界数学整数。 So given: 所以给出:
f :: Integral n => n -> n
n
could be Int
or Integer
or any "custom" type that you define that is an instance
of Integral
. n
可以是Int
或Integer
,也可以是您定义的任何“自定义”类型,它是Integral
的instance
。 The use of type classes allows for type polymorphism. 类类的使用允许类型多态。
f :: Num -> Num
WILL NOT COMPILE because Num
is not a type. f :: Num -> Num
不会编译,因为Num
不是一个类型。 Num
has kind * -> Constraint
and is thus a type constructor whereas f
requires an ordinary type or monotype which has kind *
, such as Int
or Integer
(also known as type system primitives). Num
具有类型* -> Constraint
,因此是类型构造函数,而f
需要具有类型*
的普通类型或单一类型,例如Int
或Integer
(也称为类型系统基元)。 See the haskell wiki for a brief reference/jumping off point about kinds . 请参阅haskell wiki以获取有关种类的简要参考/跳跃点。 Haskell has a rich type system with higher-order types, if used correctly it can be an extremely powerful tool ie type polymorphism. Haskell有一个具有高阶类型的丰富类型系统,如果正确使用它可以是一个非常强大的工具,即类型多态。
f :: Integer -> Integer
f
is a function from arbitrary sized integers to arbitrary sized integers. f
是从任意大小的整数到任意大小的整数的函数。
f' :: Integral n => n -> n
f'
is a polymorphic function from type n
to type n
. f'
是从n
型到n
型的多态函数。 Any type n
that is member of the class Integral
is allowed. 允许任何类型为Integral
类成员的类型n
。 Examples for types in Integral
are Integer
and Int
(the integer type with fixed precision). Integral
中类型的示例是Integer
和Int
(具有固定精度的整数类型)。
f'' :: Num n => n -> n
f''
is also a polymorphic function, but this time for class Num
. f''
也是一个多态函数,但这次是为了类Num
。 Num
is a more generic number type that has more members than Integral
, but all types in Integral
are also in contained in Num
. Num
是一种更通用的数字类型,其成员数量多于Integral
,但Integral
中的所有类型也包含在Num
。 For f''
n
can also be Double
. 对于f''
n
也可以是Double
。
TL;DR TL; DR
f :: Integer -> Integer
works for one type: Integer
. f :: Integer -> Integer
适用于一种类型: Integer
。
f :: Integral n => n -> n
works for Integer
, Int
, Word
, Int32
, Int64
, Word8
, and any arbitrary user-defined types that implement the Integral
type class. f :: Integral n => n -> n
适用于Integer
, Int
, Word
, Int32
, Int64
, Word8
以及任何实现Integral
类型类的任意用户定义类型。
That's the short version. 这是短版本。 If you only care about one type, it's easier to type-check and more efficient to execute if you specify that one type. 如果您只关心一种类型,那么如果指定一种类型,则更容易进行类型检查并且执行效率更高。 If you want multiple types, then the second way is probably the way to do. 如果你想要多种类型,那么第二种方式可能就是这样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.