【问题标题】:Haskell List Reversal ErrorHaskell 列表反转错误
【发布时间】:2010-10-05 06:04:14
【问题描述】:

我正在为 haskell 编写一个列表反转程序。

我已经有了列表反转的想法,这导致了以下代码:

myreverse list1
 | list1 == []    = list1
 | otherwise      = (myreverse(tail list1)):(head list1)

不幸的是,上面的代码导致了以下错误:

Occurs check: cannot construct the infinite type: a = [[a]]
 Expected type: [[a]]
 Inferred type: a
 In the second argument of '(:)', namely '(head list1)'
 In the expression: (myreverse(tail list1)):(head list1)

PS:当我在我写的名为 mylast 的 sn-p 上运行它时,我得到了同样的错误,代码如下:

mylast list
 | list == []      = []
 | otherwise       = mylast_helper(head list1)(tail list1)

mylast_helper item list2
 | list2 == []     = item
 | otherwise       = mylast_helper(head list2)(tail list2)

在递归助手的其他情况下发生错误。

编辑:感谢所有输入,我想我忘了提到问题的约束禁止使用 ++ 运算符。我会牢记这一点,以备将来创建问题时使用。

干杯, -紫谷

【问题讨论】:

    标签: list haskell recursion


    【解决方案1】:

    您正在使用该功能

    (:) :: a -> [a] -> [a]
    

    带有错误类型的参数:

    myReverse (tail list1) :: [a]
    head list1 :: a
    

    在您的函数中,列表 list1 必须具有类型 a。因此,第二个参数 head list1 必须具有类型 [a]。 GHC 警告您它无法构造您为其指定的类型。列表的头部在结构上小于列表的尾部,但是您告诉它列表的头部具有类型 [a],而列表尾部具有类型 一个

    但是,如果您仔细观察您的类型,您会注意到您可以将 list1 的头部追加到对 myreverse的递归调用中> 使用 (++):

    myReverse xs = case (null xs) of
                   True  -> xs
                   False -> myReverse (tail xs) ++ [head xs]
    

    这里,

    [head xs] :: [a]
    myReverse (tail xs) :: [a]
    

    append的类型一致:

    (++) :: [a] -> [a] -> [a]

    然而,有更好的方法来实现reverse。 Prelude 将 reverse 定义为左折叠(。reverse 的另一个版本可以使用右折叠来实现,并且与您的 myReverse 非常相似功能:

    reverse xs = foldr (\x xs -> xs ++ [x]) [] xs
    

    【讨论】:

      【解决方案2】:

      首先,尝试为每个函数添加签名;这将帮助编译器知道您正在尝试做什么,并在早期为您提供更好的错误消息。签名看起来像这样,例如:mylast :: [a] -> a。然后,不要使用守卫 (|),而是使用模式匹配通过一系列方程式定义您的函数:

      mylast :: [a] -> a
      mylast (x:[]) = x
      mylast (_:t) = mylast t
      

      在 GHCi 中,您可以使用 :tterm 查看某事物的类型。这是我能给出的最好的一般建议...仔细查看类型并确保它们对您的使用方式有意义。

      【讨论】:

        【解决方案3】:

        cons (:) 的类型是a -> [a] -> [a] - 换句话说,你给它一个元素,然后是一个列表,它把元素放在列表的开头。在你的最后一行中,你正在做相反的事情 - 首先是列表,然后是一个元素。要修复它,请将: 更改为列表连接运算符++

        myreverse list1
          | list1 == [] = list1
          | otherwise   = (myreverse (tail list1)) ++ [head list1]
        

        (要尝试翻译错误,它的意思是“好的,你给我的: 的第一个参数是一个列表,因此第二个参数需要是相同类型的元素列表,所以列表列表......但是......你给了我一个参数,它是列表元素的类型,所以我需要一些与该类型列表列表相同的类型,我可以'不行。砰!”)

        【讨论】:

        • 如果它编译,这将在 O(n^2) 时间内运行
        • @yatima 打错了,已修复,感谢您指出。 @pelotom 看着问题并试图衡量提问者的能力,我认为虽然它可能效率不高,但它是合适的......
        • @Jon 很公平,只是想我会指出来。 list1 == [] 的使用更成问题......这不必要地对函数强加了 Eq 类型类约束......我建议将其更改为 null list1
        • 感谢您澄清这个错误是什么。 @pelotom:这种比较会是什么样子? list1 == null?
        • @Zigu 将该行替换为 ` |空列表1 = []`
        【解决方案4】:

        结束了更多地研究这个问题并自己回答。 非常感谢您的反馈。它把我推向了正确的方向。

        myreverse list1
         | list1 == []  = list1
         | otherwise    = myreverse_h(list1)([])
        
        myreverse_h list1 list2
         | list1 == []  = list2
         | otherwise    = myreverse_h(tail list1)((head list1):list2)
        

        有更好的代码吗?我不认为它的效率尽可能高......

        【讨论】:

        • Prelude 中的实现方式大致如此。在样式方面,您可以使用模式匹配将头部与列表的尾部分开,而不是到处使用头部和尾部。此外,在函数的参数之间放置空格:myreverse_h list1 [] 看起来比到处都没有空格和括号要好得多。
        猜你喜欢
        • 2021-08-05
        • 2015-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-22
        相关资源
        最近更新 更多