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) (from Oege de Moor, Jeremy Gibbons. "Bridging the Algorithm Gap: A Linear-Time Functional Program for Paragraph Formatting" http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.47.3229 ) which is of course the natural fold for the Train data type: fold :: (a -> c -> c) -> (b -> c) -> Train a b -> c fold f g (Loco b) = g b fold f g (Wagon a t) = f a (fold f g t) Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe