You don’t offen see Maybe List except for error-handling for example, because lists are a bit Maybe themselves: they have their own “Nothing“: [] and their own “Just“: (:).
I wrote a list type using Maybe and functions to convert standard and to “experimental” lists. toStd . toExp == id.
data List a = List a (Maybe (List a))
deriving (Eq, Show, Read)
toExp [] = Nothing
toExp (x:xs) = Just (List x (toExp xs))
toStd Nothing = []
toStd (Just (List x xs)) = x : (toStd xs)
What do you think about it, as an attempt to reduce repetition, to generalize?
Trees too could be defined using these lists:
type Tree a = List (Tree a, Tree a)
I haven’t tested this last piece of code, though.
All ADTs are isomorphic (almost–see end) to some combination of
(,),Either,(),(->),VoidandMuwhereand
Mucomputes the fixpoint of a functorso for example
is the same as
which itself is isomorphic to
since
is isomorphic to
you have
which can be inlined in the mu to
and your definition
is just the unfolding of the Mu and elimination of the outer Maybe (corresponding to non-empty lists)
and you are done…
a couple of things
Using custom ADTs increases clarity and type safety
This universality is useful: see GHC.Generic
Okay, I said almost isomorphic. It is not exactly, namely
has no equivalent value in the
[a] = [] | (a:[a])definition of lists. This is because Haskell data types are coinductive, and has been a point of criticism of the lazy evaluation model. You can get around these problems by only using strict sums and products (and call by value functions), and adding a special “Lazy” data constructorand then all the isomorphisms can be faithfully encoded.