Haskell类型长度+ 1

时间:2014-09-07 01:42:04

标签: haskell

任何人都可以帮我解释长度+ 1的类型 我尝试使用以下命令:t length + 1输入ghci 它返回Num([a]->Int)=>[a]->Int 这是什么意思? THX

1 个答案:

答案 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]类型的列表。