【问题标题】:How to triple even numbers in a list?如何将列表中的偶数增加三倍?
【发布时间】:2018-05-31 22:09:48
【问题描述】:
tripleEven :: [Int] -> [Int]
tripleEven list = case list of
    []     -> []
    [x:xs]
        | (x `mod` 2) == 0 = triple x tripleEven xs
        | otherwise        = tripleEven xs
            where triple = (3*)

我不断收到以下错误:

    parse error on input `='
    Perhaps you need a 'let' in a 'do' block?
    e.g. 'let x = 5' instead of 'x = 5'
   |
71 |         | (x `mod` 2) == 0 = triple x tripleEven xs

我希望它通过一个列表,如果数字是偶数,那么它是三倍。如果它是奇数,则移动到下一个数字直到最后。我是 Haskell 的新手,只学习语法。如果有人能解释这里到底出了什么问题,我会很高兴。谢谢。

【问题讨论】:

  • 你想在输出中保留奇数吗?即tripleEven [1,2,3,4]应该是[6,12]还是[1,6,3,12]

标签: list haskell


【解决方案1】:

这里有几个问题:

  1. 您使用[x:xs] 作为非空列表模式。然而,一个列表有两个数据构造函数[](x:xs)(注意圆括号,实际上括号并不是构造函数的一部分,它只是冒号运算符(:)) ;
  2. 在右侧,您需要构建一个新列表。使用triple x tripleEven xs,您无需构建新列表:您首先计算triple x,然后Haskell 旨在以该值作为函数执行函数调用。
  3. 您还省略了奇数值:如果值为odd,您将在列表上执行递归,因此您不会将它们放入结果中。

我们可以将问题解决为:

tripleEven :: [Int] -> [Int]
tripleEven [] = []
tripleEven (x:xs) | even x = (3*x) : tripleEven xs
                  | otherwise = x : tripleEven xs

但是这里你基本上执行了一个映射:你可以调用函数到列表的每个元素,所以我们可以构造一个特殊的映射函数:

tripleEven :: [Int] -> [Int]
tripleEven = map f
    where f x | even x = 3 * x
              | otherwise = x

【讨论】:

    【解决方案2】:

    这是编写函数的递归方式,我刚刚修复了我在您的代码中注意到的错误。

    tripleEven :: [Int] -> [Int]
    tripleEven [] -> []
    tripleEven (x: xs) = case mod x 2 of
      0 -> (3*x) : tripleEven xs
      _ -> tripleEven xs
    
    tripleEven [1,2,3,4]
    # outputs
    [6, 12]
    

    TripleEven 也可以视为map & filter 操作或列表推导

    tripleEven xs = map (*3) $ filter even xs
    tripleEven xs = [x*3 | x <- xs, even x]
    

    最后,如果你想在 where 子句中定义triple

    tripleEven :: [Int] -> [Int]
    tripleEven [] = []
    tripleEven (x: xs) = case mod x 2 of
      0 -> trip x : tripleEven xs
             where trip = (*3)    
      _ -> tripleEven xs
    

    【讨论】:

    • 我不认为 OP 希望从输出中删除奇数。
    • 我将“如果它是奇数,则移动到下一个数字直到最后”解释为跳过奇数,但我知道如何以不同方式解释它
    【解决方案3】:

    列表类型是一个函子,也是一个单子。所以我相信完成这项工作的正确方法是在列表中使用fmap :: Functor f =&gt; (a -&gt; b) -&gt; f a -&gt; f b。但是,仅对于列表类型,我们已经拥有与 fmap 完全相同的 map :: (a -&gt; b) -&gt; [a] -&gt; [b] 函数。

    所以;

    Prelude> let trev = map (\n -> if even n then n*3 else n)
    Prelude> trev [1,2,3,4]
    [1,6,3,12]
    

    应该完美地完成这项工作,并且已经提到过。

    我们也可以从一元的角度来处理这个任务。然后我们需要一个单子函数来遍历我们的列表元素。 return 指令使我们的 lambda 函数在这里成为一元的。

    Prelude> let trev ns = ns >>= \n -> if even n then return (n*3) else return n
    Prelude> trev [1,2,3,4]
    [1,6,3,12]
    

    【讨论】:

      猜你喜欢
      • 2021-10-04
      • 1970-01-01
      • 2012-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-04
      • 2013-07-03
      • 1970-01-01
      相关资源
      最近更新 更多