[Haskell-cafe] Re: Are there standard idioms for lazy, pure error handling?

Heinrich Apfelmus apfelmus at quantentunnel.de
Tue Dec 1 05:29:24 EST 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)


  Oege de Moor, Jeremy Gibbons.
  "Bridging the Algorithm Gap: A Linear-Time Functional Program
    for Paragraph Formatting"


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)

Heinrich Apfelmus


More information about the Haskell-Cafe mailing list