
Excerpts from Heinrich Apfelmus's message of Tue Dec 01 11:29:24 +0100 2009:
Duncan Coutts wrote:
On Mon, 2009-11-30 at 06:08 +0000, Malcolm Wallace wrote:
However, if you really want to terminate the stream at the first error, and to reflect this in the type, then I guess you can define your own list type:
data ListThenError e a = Cons a (ListThenError e a) | Error e
Of course this has the disadvantage that then your consumer must change to use this type too.
I've been using this list type quite a lot recently. It's in the 'tar' package for example. It comes with variants of the standard functions foldl, foldr, unfoldr that take into account the error possibility.
At some point we should probably make a package to standardise and document this lazy error handling idiom.
I propose to (trivially) generalize this type to "list with an end"
data ListEnd a b = Cons a (ListEnd a b) | End b
because it may have other uses than just lazy error handling. For mnemonic value, we could call it a "train":
data Train a b = Wagon a (Train a b) | Loco b
as it is in analogy with a sequence of wagons of the same type followed by the locomotive which has a different type.
This data type naturally turns up as the differential of the lists
d [x] = Train x [x]
and the usual zipper ([x],[x]) is actually an optimization:
Train a b == ([a] , b)
Incidentally, this isomorphism corresponds to the alternative approach you mentioned:
Another approach that some people have advocated as a general purpose solution is to use:
data Exceptional e a = Exceptional { exception :: Maybe e result :: a }
As for other uses of Train , I remember seeing the following fold operation
fold1 :: (a -> b -> b) -> (a -> b) -> [a] -> b fold1 f g [a] = g a foldl f g (a:x) = f a (fold1 f g x)
This proposition looks quite nice and gently subsume the ListThenError type. type ListThenError e a = Train a (Maybe e) Anyone to put this on Hackage? -- Nicolas Pouillard http://nicolaspouillard.fr