Haskell 列表上的可能和递归
我尝试使用Haskell 列表上的可能和递归,haskell,Haskell,我尝试使用Maybe实现反转功能。我不知道如何使用递归在模式匹配中返回。例如,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)=只要$
Maybe
实现反转
功能。我不知道如何使用递归在模式匹配中返回。例如,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)=只要$myReverse-xs++[x]
就行了,但是不行,我不知道怎么做。我想知道的是怎么做以及为什么
谢谢你的帮助 myReverse
返回一个可能[a]
,它不能直接附加到某个内容,因为它不是列表。如果myReverse xs
的值为Nothing
,或者Just
。你需要对结果进行模式匹配
myReverse (x:xs) =
case myReverse xs of
Just list -> ...
Nothing -> ...
当然,您需要根据您希望myReverse
做什么来决定在这些情况下需要做什么
还请记住,并非每个函数都需要递归,因此如果需要,可以从myReverse
调用常规的reverse
。我想到了与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)
由于[a]
是一个幺半群
instance Monoid [a] where
mempty = []
mappend = (++)
那么,可能[a]
也是一个幺半群
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
强制为幺半群,否则可能a
不会
然后,我们可以使用mappend,()
,在将列表头转换为单例的条件下链接递归调用
import Data.Monoid ((<>))
myReverse :: [a] -> Maybe [a]
myReverse [] = Nothing
myReverse (x:xs) = myReverse xs <> Just [x]
这可以改写为
>>> foldl' (\x y -> y:x) [] [1..5]
[5,4,3,2,1]
为了适应Maybe类型,我们进行以下转换
- 种子
[]
变成(只是[])
- 匿名函数现在必须在内部应用,我们使用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
这将始终返回Nothing
或抛出错误,因为否则=True
。你是说更像是let reversed=myReverse'ys in in如果null reversed,那么就没有其他东西可以反转了吗
?哦,我把模式误读为一个表达式。我从未想过调用通配符大小写否则
,因为它会成为序曲的阴影。否则
。很酷的解释…那么myReverse[]
的“Nothing”呢?我们可以使用pattern guard来管理这个情况,mreverse xs | null xs=Nothing |否则=foldl'(\x y->fmap(y:)x)(Just[]))xs
我已经尝试了一段时间,但我不知道如何实现编码部分中建议的递归(我假设它应该只取代vildric代码的最后一行)。你能给我/我们一个提示吗?我能想到的应用编码部分的唯一方法是使用mappend,正如zurgl所提到的,但是case语法似乎是多余的,因为你可以编写myReverse(x:xs)=mappend(myReverse-xs)(只是[x])
。使用大小写语法:myReverse[]=Nothing;case myxs的反方向为Nothing->Just[x];否则->mappend(myReverse-xs)(仅[x])
。有没有办法在没有mappend的情况下实现编码部分?您甚至没有使用大小写绑定的值!在Just list->
案例中,list
是一个类型为[a]
的值,您可以根据需要对其执行操作。。。例如Just(list++[x])
。在任何情况下,这个答案都是“低电平”,如果它出现在我的代码中,我会认为它是一种气味;我通常更喜欢按照您的建议使用mappend
。我只是想让它对初学者来说是好的和具体的。它不起作用,或者至少我不能让它起作用。我玩弄了各种各样的表达式,包括(list++[x])
。你能展示一个没有mappend的工作示例吗?@groovy也许你可以问另一个关于它的问题?只是出于好奇,你为什么不实现与原来的reverse
函数相同的行为?为什么空列表的反面不能是空列表?是的,可以,但目标是更多地了解Haskell(面对这种问题迫使你尝试许多解决方案并寻找答案,因此你学习新事物)。
>>> 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