繁体   English   中英

Haskell的头尾init和GHCi的最后一个

[英]Haskell's head tail init and last in GHCi

我有一个关于headtailinitlast 以下在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]

正如所料,我得到了整个清单。 所以这应该适用于initlast ,对吧?

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]]

如果我查看函数的类型签名,那么headlast看起来一样 - 它们都返回一个元素。 inittail看起来也一样,因为它们都返回列表。

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 nlast 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天才能接受我自己的答案。

编辑:我得到的xxs只是按惯例选择的变量名,并且(xs:_)与头部匹配但是非常规/混淆命名。

编辑2:我赞成并接受了Daniel Wagner的回答,因为他一步一步地解释了错误信息。 非常好! 谢谢!

head / lasttail / init确实具有相同的类型。 所以,如果你只是简单地换出lastheadinittail ,你不会有任何问题:

> 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]110部分
  • Enum [[a]] - 如果init n :: a ,那么init n : last n是良好类型的,我们必须有last n :: [a] ,因此第二次出现的n必须有n :: [[a]] ; last [1..10]..部分需要Enum约束
  • Num [[a]] - 通过类似的推理,这需要做到last [1..10]110部分

但是这些约束一起很难满足 - 当然, PreludeData.List中的列表中没有EnumNum实例。 所以它抱怨。

在较大的程序中,有更多的类型信息(隐式和显式)允许编译器比提供给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是nlast 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM