任何人都可以帮我解释长度+ 1的类型我尝试用以下命令输入ghci :t length + 1
它返回Num([a]->Int)=>[a]->Int
这是什么意思?谢谢
看看的类型+
:
> :t (+)
(+) :: Num a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)
因此,两个参数必须来自同一个实例Num
,并返回其中一个.然后看看类型length
:
> :t length
length :: [b] -> Int
Run Code Online (Sandbox Code Playgroud)
(注意我已经改为在b
这里用作类型变量,但它没有改变含义).
所以,如果你有length + something
,那么length
必须有一个实现的类型Num
.由于length
已经将类型设置为[b] -> Int
,这意味着[b] -> Int
需要是一个实例Num
,并且something
必须具有相同的类型.由于Haskell中的数字文字是多态的,这意味着1
可以只具有类型Num a => a
,并且可以通过上下文选择精确的实例.因为在表达式中length + 1
,两个参数+
必须具有相同的类型,这意味着必须1
具有相同的类型,这意味着length
如果我们明确地写出所有类型,我们就会有类似的东西.
((+) :: Num ([b] -> Int) => ([b] -> Int) -> ([b] -> Int) -> ([b] -> Int))
(length :: [b] -> Int)
(1 :: [b] -> Int)
Run Code Online (Sandbox Code Playgroud)
(以前缀形式编写并分成多行,以便我们实际读取它).
基本上,这就是说,为了添加内容length
,你必须首先定义Num
for length
类型的实例.返回类型[b] -> Int
只是说它返回的东西与它的类型相同length
.
这有用吗?不,几乎可以肯定不是.这是Haskell类型系统的一个特性,你可以Num
为任何类型编写有趣和奇怪的实例,但这并不意味着Num
每种类型的实例都是有用的,可以通过智能方式定义,甚至可以在不诉诸的情况下实现undefined
.
我们可以Num
为这种类型编写一个实例,但我会选择在一个内部编写它,newtype
因为它可以让我们避免语言扩展.
newtype Silly a = Silly { unSilly :: [a] -> Int }
instance Num (Silly a) where
fromInteger x = Silly $ const (fromInteger x)
Silly f + Silly g = Silly $ \l -> f l + g l
Silly f * Silly g = Silly $ \l -> f l * g l
negate (Silly f) = Silly $ negate . f
abs (Silly f) = Silly $ abs . f
signum (Silly f) = Silly $ signum . f
Run Code Online (Sandbox Code Playgroud)
然后我们可以用它作为
> (unSilly $ Silly length + 1) [1, 2, 3]
4
> (unSilly $ Silly length * Silly length) [1, 2, 3, 4]
16
> (unSilly $ negate $ Silly length) [1, 2, 3]
-3
Run Code Online (Sandbox Code Playgroud)
但这并不是真的有用,它增加了相当多的样板来做相当于的事情
> length [1, 2, 3] + 1
4
> length [1, 2, 3, 4] * length [1, 2, 3, 4]
16
> negate $ length [1, 2, 3]
-3
Run Code Online (Sandbox Code Playgroud)
虽然在某些例子中有点酷:
> (unSilly $ Silly head + Silly last) [10, 0, 1, 2, 3, 4, 5]
15
Run Code Online (Sandbox Code Playgroud)
但这仅适用于类型列表[Int]
.