【问题标题】:infinite type error reversing a list in Haskell在 Haskell 中反转列表的无限类型错误
【发布时间】:2021-08-05 02:46:16
【问题描述】:

我正在尝试实现列表的反转:

myLast :: [a] -> a
myLast [] = error "No end for empty lists!"
myLast [x] = x
myLast (_:xs) = myLast xs

myReverse :: [a] -> [a]
myReverse (x:xs) = myLast xs + myReverse xs

但我收到此错误:

/workspaces/hask_exercises/exercises/src/Lib.hs:42:32: error:
    * Occurs check: cannot construct the infinite type: a ~ [a]
    * In the second argument of `(+)', namely `myReverse xs'
      In the expression: myLast xs + myReverse xs
      In an equation for `myReverse':
          myReverse (x : xs) = myLast xs + myReverse xs
    * Relevant bindings include
        xs :: [a] (bound at src/Lib.hs:42:14)
        x :: a (bound at src/Lib.hs:42:12)
        myReverse :: [a] -> [a] (bound at src/Lib.hs:41:1)
   |
42 | myReverse (x:xs) = myLast xs + myReverse xs
   |                                ^^^^^^^^^^^^

cannot construct the infinite type: a ~ [a] 是什么意思?我经常收到此错误,并想了解它的含义。

【问题讨论】:

  • 你认为+ 会做什么?
  • ++ 用于连接列表。
  • @JosephSible-ReinstateMonica myLast xs 是一个数字,myReverse xs 是一个列表,所以它应该将数字添加到列表中
  • + 用于将数字相加。 : 将一个元素粘贴到一个列表中,++ 连接两个列表。

标签: list haskell types infinite


【解决方案1】:

(+) :: Num a => a -> a -> a 函数将两个数字(相同类型)相加。所以例如如果a ~ Int,它将添加两个Ints,但不是Int[Int]

但是,即使 (+) 运算符例如会将项目添加到列表中,它仍然无法正确反转列表:您的函数没有基本情况对空列表做什么,并且您的递归列表对列表(x:xs) 的第一项x 没有任何作用。

简单的反转方法:

myReverse :: [a] -> [a]
myReverse [] = []
myReverse (x:xs) = myReverse xs ++ [x]

但这并不高效:追加两个项目将花费左列表大小的线性时间。您可以使用累加器:每次进行递归调用时都会更新的参数。这看起来像:

myReverse :: [a] -> [a]
myReverse [] = go []
    where go ys (x:xs) = …
    where go ys [] = …

填写部分留作练习。

【讨论】:

    【解决方案2】:

    你有

    myLast :: [a] -> a 
    myReverse :: [a] -> [a]
    
    myReverse (x:xs) = myLast xs    +     myReverse xs
                       \___a___/          \____[a]___/
    
              (x:xs)  :: [a]
              ---------------
               x      ::  a
                 xs   :: [a]                        xs :: [a]               
          myLast      :: [a] -> a         myReverse    :: [a] -> [a]
         -------------------------       ----------------------------
          myLast xs   ::        a         myReverse xs ::        [a]
    
    myReverse (x:xs)                                   ::        [a]
    

    但是

    > :t (+)
                                   (+) :: Num a =>  a  ->  a  ->  a
    

    表示+左边的东西的类型和右边的东西的类型必须相同。

    但它们不可能是:正如我们刚刚在上面看到的,在您的代码中,第一个(myLast xs)是某种类型a,第二个(myReverse xs)是[a] 列表相同的as。

    这两个不能相同,因为这意味着

                  a  ~  [a]             OK, this is given to us, then
                         a  ~ [a]       we can use it, so that
                     --------------
                  a  ~ [[a]]            this must hold;
                         a  ~ [a]       we know this, then
                     --------------
                 a  ~ [[[a]]]           this must also hold; and
                         a  ~ [a]       ........
                     --------------     ........
                 a ~ [[[[a]]]]          ........
              .........................
    

    以此类推,无限循环,从而使a 成为“无限”类型。因此出现错误。

    您可以通过将 + 替换为

    来修复它
                                  (+++) ::         a  ->  [a]  ->  [a]
    

    并实施它来做你需要做的事情。

    您还需要修复 off-by-one 错误,从而完全忽略接收到的输入中的第一个元素 x

    【讨论】:

      猜你喜欢
      • 2012-09-29
      • 1970-01-01
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 2015-01-06
      • 1970-01-01
      • 1970-01-01
      • 2012-01-06
      相关资源
      最近更新 更多