也许和列表上的递归

时间:2013-04-13 23:03:45

标签: haskell

我尝试使用reverse实现Maybe功能。我不知道如何使用递归在模式匹配中返回Just。例如,ghci> myReverse [1,2,3]需要返回Just [3,2,1]。这是我的代码:

myReverse :: [a] -> Maybe [a]
myReverse [] = Nothing
myReverse [x] = Just [x]
myReverse (x:xs) = myReverse xs ++ [x] -- here's my problem.

我认为myReverse (x:xs) = Just $ myReverse xs ++ [x]有效,但没有,我不知道怎么做。我想知道的是如何做到这一点以及为什么。

感谢您的帮助!

3 个答案:

答案 0 :(得分:4)

myReverse会返回Maybe [a],但不能将其直接附加到某个内容,因为它不是列表。 IOW myReverse xs的值可以是Nothing,也可以是Just <some list>。您需要对结果进行模式匹配。

myReverse (x:xs) = 
    case myReverse xs of
         Just list -> ...
         Nothing   -> ...

当然,您需要决定在每种情况下需要做些什么,具体取决于您希望myReverse做什么。

另请注意,每个函数都不需要递归,因此如果需要,可以从reverse调用常规myReverse

答案 1 :(得分:4)

由于[a] Monoid 定义,

instance Monoid [a] where
        mempty  = []
        mappend = (++)

然后Maybe [a]也是 Monoid

instance Monoid a => Monoid (Maybe a) where
    mempty = Nothing
    Nothing `mappend` m = m
    m `mappend` Nothing = m
    Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)

请注意实例声明中的类型约束,它将a强加为Monoid,否则Maybe a不会。

然后我们可以使用mappend (<>)来链接我们的递归调用,以便将列表的头部转换为单例。

import Data.Monoid ((<>))

myReverse :: [a] -> Maybe [a]
myReverse []     = Nothing
myReverse (x:xs) = myReverse xs <> Just [x]

最后请注意,之前的折叠解决方案也可以改进。

>>> let mrev = foldl' (\x y -> Just [y] <> x ) Nothing
>>> mrev []
Nothing
>>> mrev "hello"
Just "olleh"

上一个折叠答案

知道可以使用折叠定义反向,如下所示

>>> foldl' (flip (:)) [] [1..5]
[5,4,3,2,1]

这可以改写为,

>>> foldl' (\x y -> y:x) [] [1..5]
[5,4,3,2,1]

为了适应Maybe类型,我们进行以下转换,

  • 种子[]变为(Just [])
  • 现在必须在匿名函数中应用Just,我们使用fmap来完成它。

这引导我们,

>>> foldl' (\x y -> fmap (y:) x) (Just []) [1..5]
Just [5,4,3,2,1]

最后,

mreverse xs | null xs = Nothing 
            | foldl' (\x y -> fmap (y:) x) (Just []) xs

答案 2 :(得分:1)

我想到了luqui的一些东西,除了最后应用了Maybe:

myReverse :: [a] -> Maybe [a]
myReverse ys
  | null (myReverse' ys) = Nothing
  | otherwise            = Just (myReverse' ys)
 where
   myReverse' []     = []
   myReverse' (x:xs) = myReverse' xs ++ [x]

或者,如果你愿意的话,

myReverse ys | null (reverse ys) = Nothing
             | otherwise         = Just (reverse ys)