首先,我有一个(无限的)Eithers 列表,它的生成方式如下:
x :: A
...
f :: A -> Either B A
...
xs :: [Either B A]
xs = iterate (>>=f) (Right x)
该列表将包含几个Rights (总是一个有限的数字),然后Left重复相同的值。我需要的是把所有的Rights 和一个Left在他们之后。在这种特殊情况下,例如也可以通过更改函数来完成,但我也对最佳通用方法感兴趣。
让我提出一个更具侵略性的改变。代替
x :: A
f :: A -> Either B A
xs :: [Either B A]
考虑
x :: A
f :: A -> Writer [A] B
并完全忘记xs。以前f是单步迭代,现在是递归的;以前它会回来的地方Right a,你现在tell [a] >> f a;以前它会回来的地方Left b,你现在return b。
如果确实有必要,您仍然可以访问 的各个部分Writer,即[A]and B,通过execWriterand evalWriter(或使用runWriter同时访问它们):
xs :: [A]
b :: B
(xs, b) = runWriter (f x)
您可以使用在元素和元素span之间拆分列表,然后进行模式匹配以获取第一个.RightLeftLeft
(rights, firstLeft : _) = span isRight xs
where isRight (Right _) = True
isRight _ = False
如果您需要将它们全部保存在同一个列表中,我会这样做:
answer = map fst . takeWhile snd $ zip xs (True : map isRight xs)
where isRight (Right _) = True
isRight _ = False
(为什么不在Data.Either中定义isRight和定义?)isLeft