![](/img/trans.png)
[英]Pattern match against List 'init' and 'last' instead of 'head' and 'tail'
[英]Haskell's head tail init and last in GHCi
我有一个关于head
, tail
, init
和last
。 以下在GHCi中有效:
Prelude Data.List Data.Char> let n = [1..10] in (head n : tail n)
[1,2,3,4,5,6,7,8,9,10]
正如所料,我得到了整个清单。 所以这应该适用于init
和last
,对吧?
Prelude Data.List Data.Char> let n = [1..10] in (init n : last n)
<interactive>:39:1:
Non type-variable argument in the constraint: Enum [[a]]
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall a. (Enum a, Enum [[a]], Num a, Num [[a]]) => [[a]]
如果我查看函数的类型签名,那么head
和last
看起来一样 - 它们都返回一个元素。 init
和tail
看起来也一样,因为它们都返回列表。
Prelude Data.List Data.Char> :info head
head :: [a] -> a -- Defined in ‘GHC.List’
Prelude Data.List Data.Char> :info tail
tail :: [a] -> [a] -- Defined in ‘GHC.List’
Prelude Data.List Data.Char> :info init
init :: [a] -> [a] -- Defined in ‘GHC.List’
Prelude Data.List Data.Char> :info last
last :: [a] -> a -- Defined in ‘GHC.List’
那么Non type-variable argument in the constraint: Enum [[a]]
中的Non type-variable argument in the constraint: Enum [[a]]
什么Non type-variable argument in the constraint: Enum [[a]]
是什么意思? 如果我在没有构建新列表的情况下执行init n
或last n
,我得到[1..9]
和10
。
啊,快照:
接受一个元素,其余像x:xs
,而不是列表和最后一个元素,就像在xs:x
。
Prelude Data.List Data.Char> :info :
data [] a = ... | a : [a] >·-- Defined in ‘GHC.Types’
infixr 5 :
data [] a = ... | a : [a] >·-- Defined in ‘GHC.Types’
infixr 5 :
我仍然想知道您如何理解GHCi错误消息,我还是要等待2天才能接受我自己的答案。
编辑:我得到的x
和xs
只是按惯例选择的变量名,并且(xs:_)
与头部匹配但是非常规/混淆命名。
编辑2:我赞成并接受了Daniel Wagner的回答,因为他一步一步地解释了错误信息。 非常好! 谢谢!
head
/ last
和tail
/ init
确实具有相同的类型。 所以,如果你只是简单地换出last
的head
和init
的tail
,你不会有任何问题:
> let n = [1..10] in last n : init n
[10,1,2,3,4,5,6,7,8,9]
但你没有。 你做了交换和另一个 :你改变了参数的顺序:
。 碰巧的是:
不采用相同类型的两个参数:
> :t (:)
(:) :: a -> [a] -> [a]
所以这最后一次交换不行! 事实上,如果你给n
一个稍微更具体的类型签名,ghci的会给出更好的错误:
> let n :: [Integer]; n = [1..10] in init n : last n
<interactive>:1:50:
Couldn't match type ‘Integer’ with ‘[[Integer]]’
Expected type: [[[Integer]]]
Actual type: [Integer]
In the first argument of ‘last’, namely ‘n’
In the second argument of ‘(:)’, namely ‘last n’
这个错误仍然没有100%明确,但我想有点令人费解你可以看到它抱怨的内容:因为init n :: [Integer]
和(:) :: [Integer] -> [[Integer]] -> [[Integer]]
,它期望last n :: [[Integer]]
,因此n :: [[[Integer]]]
。 但你明确地说n :: [Integer]
是一个冲突。
现在,它在你的情况下实际给你的错误怎么样? 那么,线索的类型为[1..10]
:
> :t [1..10]
[1..10] :: (Enum t, Num t) => [t]
请注意, [1..10]
是多态的。 而且,它在你的表达式中使用了两次,因此在两种用法中它可以被赋予单独的单态类型。 所以[1..10]
在续集中用两种不同的类型进行实例化!
现在我想你可以开始看到你得到的错误在哪里。它正试图找到一个类型a
:
Enum a
-这是应该做的需要..
的一部分init [1..10]
Num a
- 这需要执行init [1..10]
的1
和10
部分 Enum [[a]]
- 如果init n :: a
,那么init n : last n
是良好类型的,我们必须有last n :: [a]
,因此第二次出现的n
必须有n :: [[a]]
; last [1..10]
的..
部分需要Enum
约束 Num [[a]]
- 通过类似的推理,这需要做到last [1..10]
的1
和10
部分 但是这些约束一起很难满足 - 当然, Prelude
或Data.List
中的列表中没有Enum
和Num
实例。 所以它抱怨。
在较大的程序中,有更多的类型信息(隐式和显式)允许编译器比提供给GHCi的单行代码片段更好地推断类型。 因此,您在GHCi中看到的错误并不代表构建完整程序时通常观察到的错误。
也就是说,这不是你发布的错误的可怕原因:
Prelude> let n = [1..10] in (init n : last n)
<interactive>:8:1:
Non type-variable argument in the constraint: Enum [[a]]
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall a. (Enum a, Enum [[a]], Num a, Num [[a]]) => [[a]]
所以你自己的行中涉及很多多态性。 你有Num a( Num a => [a]
)的列表,其中类型变量a
本身必须是alist,因为你已经使用过: last n
where last n :: [_] ~ a
。 所以这一点,再加上列表理解中的..
意味着一个枚举,就是我们如何得到这个可怕的信息。
让我们看看更简单的情况,我们告诉GHCi我们的列表是[Int]
类型:
Prelude> let n = [1..10] :: [Int] in (init n : last n)
<interactive>:7:44:
Couldn't match type ‘Int’ with ‘[[Int]]’
Expected type: [[[Int]]]
Actual type: [Int]
In the first argument of ‘last’, namely ‘n’
In the second argument of ‘(:)’, namely ‘last n’
啊,好多了。 列44是n
在last n
。 它说last n :: Int
。 所以init n :
的类型init n :
当init n :: [Int]
意味着我们的cons函数类型是(:) :: [Int] -> [[Int]] -> [[Int]]
。 可是等等! init n :
的参数所需的[[Int]]
与last n
提供的Int
不匹配!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.