我尝试使用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]
有效,但没有,我不知道怎么做。我想知道的是如何做到这一点以及为什么。
感谢您的帮助!
答案 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 [])
这引导我们,
>>> 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)