Haskell中的mapEithers函数
以下功能如何工作:Haskell中的mapEithers函数,haskell,map-function,Haskell,Map Function,以下功能如何工作: mapEithers :: (a -> Either b c) -> [a] -> Either b [c] mapEithers f (x:xs) = case mapEithers f xs of Left err -> Left err Right ys -> case f x of
mapEithers :: (a -> Either b c) -> [a] -> Either b [c]
mapEithers f (x:xs) = case mapEithers f xs of
Left err -> Left err
Right ys -> case f x of
Left err -> Left err
Right y -> Right (y:ys)
mapEithers _ _ = Right []
在第一个case表达式(
case mappeithers f xs
)中,当函数f
尚未应用于列表元素时,它如何与Left
和Right
值进行模式匹配。这是经典的递归,我们将mapEithers
应用于一个子列表,生成类型为b[c]
,如果它是左侧的b
,我们只是通过它传播它
如果是右cs
。然后我们将f
应用于列表的开头。如果这产生了一个错误,我们将删除所有内容并向上传播,如果它是正确的c
,那么结果是正确的(c:cs)
因为我们需要一个重复的基本情况,一个空列表是记录的
Right[]
,这可以用折叠来写。在真实的Haskell代码中,很少看到显式递归。相反,我们有一系列函数(除其他函数外,fold
,replicItem
,map
,filter
),它们为我们完成了“繁重的工作”,我们只需要提供一些参数,在使用它们时对它们进行一些定制
在本例中,您有两个值,一个是列表其余部分的结果,另一个是当前值的结果。如果两者都是右侧
,则希望它们一起列在一个列表中,如果它们都是左侧
,则只希望保留错误消息
我在Haskell中所描述的可以写成
(:) <$> f elem <*> rest
mapEithers f = foldr (\elem rest -> (:) <$> f elem <*> rest) (Right [])
编辑:我刚刚意识到,通过一些额外的转换,它可以变得更简单。(但我的哈斯克尔赋不够强壮,无法流利地阅读此文……)
它与递归调用mapEithers
的结果相匹配,后者是一个b[c]
。但是当您将mapEithers
应用于子列表时,由于递归,会再次调用mapEithers
。这会一直持续到列表变为空,在这种情况下,它应该返回Right[]
。但这并没有发生。我在推断什么是错的?@Sibi相反,这正是发生的事情。你看到了什么?你是否错过了第二部分,在它变成Right[]
之后,所有东西都会重新构建?见第二小段谢谢,现在明白了。:-)MapOrther
与使用mapM
几乎相同,只是后者选择在第一个左侧的结果上进行快捷操作,而不是像MapOrther
那样在最后一个结果上进行快捷操作。
mapEithers f = foldr (liftA2 (:) . f) (Right [])