任何人都可以帮我解释长度+ 1的类型
我尝试使用以下命令:t length + 1
输入ghci
它返回Num([a]->Int)=>[a]->Int
这是什么意思?
THX
答案 0 :(得分:9)
查看+
的类型:
> :t (+)
(+) :: Num a => a -> a -> a
因此,两个参数必须来自Num
的同一个实例,并返回其中一个。然后查看length
的类型:
> :t length
length :: [b] -> Int
(请注意,我已更改为在此处使用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)
(以前缀形式书写并分成多行,以便我们实际读取它。)
基本上,这就是为了向length
添加内容,您必须首先为Num
类型定义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
然后我们可以将它用作
> (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
但这并不是非常有用,它增加了相当多的样板来做等同于
的事情。> length [1, 2, 3] + 1
4
> length [1, 2, 3, 4] * length [1, 2, 3, 4]
16
> negate $ length [1, 2, 3]
-3
虽然在某些例子中有点酷:
> (unSilly $ Silly head + Silly last) [10, 0, 1, 2, 3, 4, 5]
15
但这仅适用于[Int]
类型的列表。