列表对递归的理解[Haskell]

时间:2015-01-12 18:52:08

标签: list haskell recursion list-comprehension

我有以下函数,它将Maybes列表与Int输入分开。

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

3 个答案:

答案 0 :(得分:4)

你快到了。

  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)
    
  3. 下面,

    divideList _ [] = []
    

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

答案 1 :(得分:3)

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

相反,要弄清楚如何使用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

答案 2 :(得分:1)

我建议先写一个函数来分割两个整数。它必须返回Maybe Double,因为计算不可能。

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

然后您只需要将此函数应用于列表的每个元素,这可以使用map来完成。但是,因为数字是隐藏的&#34;在Maybe中,您可以使用函数(>>=)来&#34;展开&#34;它(当它不是Nothing时,它会保持Nothing,如我们所愿。)

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

或更短:

divideList m = map (>>= div2 m)