【问题标题】:Haskell: Parse error in pattern x ++ xsHaskell:模式 x ++ xs 中的解析错误
【发布时间】:2017-10-29 17:31:27
【问题描述】:

third of the 99-Haskell problems(我目前正在尝试学习该语言)我尝试将模式匹配和递归合并到我的函数中,现在看起来像这样:

myElementAt :: [a] -> Int -> a
myElementAt (x ++ xs) i =
  if length (x ++ xs) == i && length xs == 1 then xs!!0
  else myElementAt x i

这给了我Parse error in pattern: x ++ xs。问题:

  1. 为什么会出现解析错误?是不是因为 Haskell 不知道从哪里删减我的清单(这是我最好的猜测)?
  2. 如何重新构建我的函数以使其正常工作?算法思想是检查列表是否具有指定inde的长度;如果是,则返回最后一个元素;如果不删除列表末尾的一个元素,然后进行递归。

注意:我知道这是一个非常糟糕的算法,但我已经为自己设定了编写该函数的挑战,包括递归和模式匹配。我还尝试不使用 !! 运算符,但这对我来说很好,因为它唯一真正做的事情(或者如果它编译了应该做的事情)就是将一个元素列表转换为该元素。

【问题讨论】:

  • 除了模式匹配问题,请注意您的算法非常效率低下:length 已经需要遍历整个列表。如果您随后对此进行递归,那么对于简单的查找,您最终会得到 O (n ²) 的复杂度!

标签: haskell pattern-matching parse-error


【解决方案1】:

大概,您正在尝试匹配列表的头部和尾部。让我们一步一步来:

myElementAt (x:_) 0 = x

这意味着如果头部是x,尾部是东西,并且索引为0,则返回头部。请注意,您的 x ++ x 是两个列表的串联,而不是头部和尾部。

那么你可以拥有

myElementAt(_:tl) i = myElementAt tl (i - 1)

表示如果前面的模式不匹配,忽略头部,取尾部的i - 1元素。

【讨论】:

    【解决方案2】:

    Haskell 有两种不同类型的值级实体:变量(这也包括函数、++ 等中缀运算符)和构造函数。两者都可以用在表达式中,但只有构造函数也可以用在模式中。

    无论哪种情况,很容易判断您是在处理变量还是构造函数:构造函数总是以大写字母开头(例如NothingTrueStateT),或者,如果它是一个中缀, 带有冒号 (:, :+)。其他一切都是变量。从根本上说,不同之处在于构造函数始终是来自预定义集合(即data 定义的替代方案)的唯一、可立即匹配的值,而变量只能具有任何值,并且通常原则上不可能唯一区分不同的变量,特别是如果它们具有函数类型。

    你的实际上是一个很好的例子:为了使模式匹配 x ++ xs 有意义,必须有一种独特的方式,其中输入列表可以以 @ 的形式写入987654333@。好吧,但是对于 [0,1,2,3] 来说,有多种不同的方法可以做到这一点:

    [] ++[0,1,2,3]
    [0] ++ [1,2,3]
    [0,1] ++ [2,3]
    [0,1,2] ++ [3]
    [0,1,2,3]++ []
    

    运行时应该选择哪一个?

    【讨论】:

      【解决方案3】:

      在模式中,您只能使用 :[] 这样的构造函数。追加操作符(++) 是一个非构造函数。

      所以,试试这样的:

      myElementAt :: [a] -> Int -> a
      myElementAt (x:xs) i = ...
      

      您的代码中还有更多问题,但至少这解决了您的第一个问题。

      【讨论】:

        【解决方案4】:

        在标准 Haskell 模式中匹配如下:

        f :: Int -> Int
        f (g n 1) = n
        
        g :: Int -> Int -> Int
        g a b = a+b
        

        是非法的,因为模式中不允许函数调用,您的情况只是一个特殊情况,因为运算符 ++ 只是一个函数。

        要在列表上进行模式匹配,您可以这样做:

        myElementAt :: [a] -> Int -> a
        myElementAt (x:xs) i = // result
        

        但在这种情况下 x 的类型是 a 而不是 [a] ,它是列表的头部,xs 是它的尾部,您需要更改函数实现以适应这一事实,此函数也会因空列表[] 而失败。然而,这是模式匹配 aginst 列表的惯用 haskell 方式。

        我应该提到,当我说“非法”时,我的意思是在标准 Haskell 中,有一些 GHC 扩展提供了类似的东西,它被称为 ViewPatterns 但我认为你不需要它,尤其是你仍然学习。

        【讨论】:

          猜你喜欢
          • 2014-07-03
          • 2012-01-23
          • 2013-01-29
          • 1970-01-01
          • 2013-05-08
          • 2015-03-14
          • 2012-12-24
          • 2012-09-28
          • 2019-05-03
          相关资源
          最近更新 更多