【问题标题】:Haskell Replace a value in a list with another valueHaskell 用另一个值替换列表中的值
【发布时间】:2017-08-27 23:36:20
【问题描述】:

我对 Haskell 很陌生。我正在尝试编写一个程序,它接受两个值和一个列表,并用第二个替换列表中第一个值的每个实例。例如。 repOcc 'n' 'i' "pink" 将返回 "piik"

以下是我的代码:

repOcc :: t -> t -> [t] -> [t]
repOcc x y (z:zs) = if z == x
                      then z = y
                      subst x y zs
                      else subst x y zs

我在编译时收到的错误是:

rev.hs:3 :32: error: 
   parse error on input '='
   Perhaps you need a 'let' in a 'do' block?
   e.g. 'let x = 5' instead of 'x = 5'
Failed, modules loaded: none.

【问题讨论】:

  • 请说明代码与您的预期有何不同。有编译器错误吗?那是什么错误?程序是否给出不正确的输出?输入和错误输出的示例是什么?
  • 开始更简单:如果x 等于fromx 否则不变,你能写一个函数f from to x 计算为to 吗?
  • 编译时出现解析错误,编译器建议我在“do block”中添加“let”
  • @RNee 请编辑您的问题以包含解析错误的确切文本。
  • 进入 Haskell 的第一步就是忘记你曾经听说过的任务。

标签: haskell


【解决方案1】:

您的程序看起来更像“命令式”,而 Haskell 的目标是更“声明式”。所以你不能在列表中设置变量z:一旦构造了列表,你就不能再改变它了。所以你必须构造一个新列表,其中等于x 的元素设置为y

接下来您将使用(==) 函数。该函数在Eq 类型类中定义,因此您需要将Eq t 作为类型约束添加到签名中。

所以现在我们可以开始构造这样的函数了。通常在处理列表时,我们会使用递归。递归的基本情况通常是空列表。如果我们遇到空列表,我们应该返回一个空列表,不管 xy 是什么。所以我们使用下划线作为“don't care”模式,使用[]作为列表模式,并写:

repOcc _ _ [] = []

递归情况是列表包含(h:t) 模式中的头部h 和尾部t。在这种情况下,我们检查h 是否等于x。如果是,我们构造一个以y为头的列表,否则h仍然是头。

repOcc x y (h:t) | x == h = y : tl
                 | otherwise = h : tl

现在的问题仍然是结果列表tl 的尾部应该是什么。这里我们使用递归,所以我们用x y t调用repOcc

    where tl = repOcc x y t

或者把它放在一起:

repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc _ _ [] = []
repOcc x y (h:t) | x == h = y : tl
                 | otherwise = h : tl
    where tl = repOcc x y t

我们可以编写这样的递归函数,但上面实际上是map函数的一个特例:我们映射每个字符的方式是检查它是否等于x,如果是,我们返回y,否则我们返回h。所以我们可以将上面的内容改写为:

repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc x y ls = map (\h -> if h == x then y else h) ls

我们可以利用 eta-reduction 进一步改进代码:

repOcc :: Eq t => t -> t -> [t] -> [t]
repOcc x y = map (\h -> if h == x then y else h)

【讨论】:

    猜你喜欢
    • 2021-06-16
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 2021-10-11
    • 2020-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多