【问题标题】:List Comprehension to Recursion [Haskell]递归列表理解 [Haskell]
【发布时间】:2015-03-10 14:55:24
【问题描述】:

我有以下函数,它用一个 Int 输入来划分一个 Maybes 列表。

divideList :: Int -> [Maybe Int] -> [Maybe Double]

 divideList 100 [Just 5, Just 4, Nothing]   == [Just 20, Just 25.0, Nothing]

提醒一下,Maybe 数据类型定义如下:

 data Maybe a = Nothing | Just a

我的代码看起来(和工作)如下:

divideList m xs = [ div2 x | x <- xs]
    where
        div2 (Just n) | n > 0   = Just (fromIntegral m / fromIntegral n)
        div2 _                  = Nothing

现在我正在尝试再次编写相同的函数,但这次只是使用递归且没有列表推导。但是我似乎无法让它工作。

这是我的(错误的)猜测:

divideList m xs = div2  x 
    where
        div2 (Just x) | x > 0   = Just (fromIntegral m / fromIntegral x)
        div2 _                  = Nothing

【问题讨论】:

    标签: list haskell recursion list-comprehension


    【解决方案1】:

    我建议先编写一个除以两个整数的函数。它必须返回一个Maybe Double,因为计算并不总是可行的。

    div2 m n = if n <= 0 then Nothing else Just (fromIntegral m / fromIntegral n)
    

    然后你只需要将这个函数应用到列表的每个元素上,这可以通过map 来完成。然而,由于数字在Maybe 中“隐藏”,您可以使用函数(&gt;&gt;=) 来“解包”它(当它不是Nothing 时,它仍然是Nothing,如我们所愿) .

    divideList m xs = map (>>= div2 m) xs
    

    或更短:

    divideList m = map (>>= div2 m)
    

    【讨论】:

      【解决方案2】:

      我始终建议这样做:不要像您正在尝试做的那样编写直接递归解决方案。它们不是惯用的,它们更难阅读,一旦你做任何复杂的事情,它们就很难写。

      相反,请弄清楚如何使用标准库函数(如 mapfilter 等)编写您的解决方案。然后,作为练习,编写您自己版本的这些库函数。在这种情况下:

      divideList m xs = map div2 xs
          where
              div2 (Just n) | n > 0   = Just (fromIntegral m / fromIntegral n)
              div2 _                  = Nothing
      
      -- Apply the function `f` to each element of the list, returning a list of the results,
      -- in the order of the corresponding arguments.
      map f []     = _   -- Fill me in
      map f (x:xs) = _   -- Fill me in
      

      【讨论】:

        【解决方案3】:

        你快到了。

        1. 先单独定义除法函数

          div3 :: Int -> Maybe Int -> Maybe Double
          div3 i (Just n) | n > 0 = Just (fromIntegral i / fromIntegral n)
          div3 i _                = Nothing
          
        2. 然后,对于列表中的每个项目,调用 div3 并将其与递归调用 divideList 的结果连接起来,像这样

          divideList :: Int -> [Maybe Int] -> [Maybe Double]
          divideList _ [] = []
          divideList m (x:xs) = (div3 m x):(divideList m xs)
          

        这里,

        divideList _ [] = []
        

        被称为递归的基本条件。这决定了您的递归何时结束。

        【讨论】:

        • 我想提一下,这本质上是map 专用于div3 的函数。
        • @bheklilr 因为他已经知道列表理解,我们可以放心地假设他也知道map,我猜。 :)
        猜你喜欢
        • 2017-02-10
        • 1970-01-01
        • 2019-07-21
        • 2011-07-09
        • 1970-01-01
        • 1970-01-01
        • 2020-10-17
        • 1970-01-01
        • 2013-01-17
        相关资源
        最近更新 更多