列表理解递归 [Haskell]
List Comprehension to Recursion [Haskell]
我有以下函数,它用 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
你快到了。
先单独定义除法函数
div3 :: Int -> Maybe Int -> Maybe Double
div3 i (Just n) | n > 0 = Just (fromIntegral i / fromIntegral n)
div3 i _ = Nothing
然后,对于列表中的每个项目,调用 div3
并将其与递归调用 divideList
的结果连接起来,就像这样
divideList :: Int -> [Maybe Int] -> [Maybe Double]
divideList _ [] = []
divideList m (x:xs) = (div3 m x):(divideList m xs)
这里,
divideList _ [] = []
称为递归的基本条件。这决定了递归何时结束。
我一直建议的是:不要 像您尝试做的那样编写直接递归解决方案。它们不是惯用的,更难阅读,而且一旦你做任何复杂的事情,它们就会变得很难写。
相反,弄清楚如何使用 map
、filter
等标准库函数编写您的解决方案。然后,作为练习,编写您自己的这些库函数版本。在这种情况下:
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
我建议先写一个函数来除两个整数。它必须 return 一个 Maybe Double
,因为计算并不总是可行的。
div2 m n = if n <= 0 then Nothing else Just (fromIntegral m / fromIntegral n)
然后你只需要将这个函数应用到列表的每个元素,这可以用map
来完成。但是,由于 Maybe
中的数字是 "hidden",您可以使用函数 (>>=)
来 "unwrap" 它(当它不是 Nothing
时,它保持 Nothing
,如我们所愿)。
divideList m xs = map (>>= div2 m) xs
或更短:
divideList m = map (>>= div2 m)
我有以下函数,它用 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
你快到了。
先单独定义除法函数
div3 :: Int -> Maybe Int -> Maybe Double div3 i (Just n) | n > 0 = Just (fromIntegral i / fromIntegral n) div3 i _ = Nothing
然后,对于列表中的每个项目,调用
div3
并将其与递归调用divideList
的结果连接起来,就像这样divideList :: Int -> [Maybe Int] -> [Maybe Double] divideList _ [] = [] divideList m (x:xs) = (div3 m x):(divideList m xs)
这里,
divideList _ [] = []
称为递归的基本条件。这决定了递归何时结束。
我一直建议的是:不要 像您尝试做的那样编写直接递归解决方案。它们不是惯用的,更难阅读,而且一旦你做任何复杂的事情,它们就会变得很难写。
相反,弄清楚如何使用 map
、filter
等标准库函数编写您的解决方案。然后,作为练习,编写您自己的这些库函数版本。在这种情况下:
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
我建议先写一个函数来除两个整数。它必须 return 一个 Maybe Double
,因为计算并不总是可行的。
div2 m n = if n <= 0 then Nothing else Just (fromIntegral m / fromIntegral n)
然后你只需要将这个函数应用到列表的每个元素,这可以用map
来完成。但是,由于 Maybe
中的数字是 "hidden",您可以使用函数 (>>=)
来 "unwrap" 它(当它不是 Nothing
时,它保持 Nothing
,如我们所愿)。
divideList m xs = map (>>= div2 m) xs
或更短:
divideList m = map (>>= div2 m)