[clean-list] key mapping

Richard A. O'Keefe ok@atlas.otago.ac.nz
Thu, 5 Apr 2001 14:05:28 +1200 (NZST)


	Another question with the following code:
	        get :: Int Int (Mat Int) -> Int
	        get 0 _ _= ? <- How can I return nothing or better an error?
	        get x y mat= nth y (nth x mat)
	
In SML, you would write

	val get : int -> int -> int mat -> int option
	...
	fun get 0 _ _   = NONE
	  | get x y mat = SOME (nth y (nth x mat))

In Haskell, you would write

	get :: Int -> Int -> (Mat Int) -> Maybe Int
	get 0 _ _   = Nothing
	get x y mat = Just (nth y (nth x mat))

A couple of years ago I wrote versions of Maybe and Option for Clean.
Use Option if you like the SML names, but Clean is closer to Haskell,
so it'd probable be better to use Maybe.

I enclose a shar file with interfaces and implementations.

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Maybe.dcl
#	Maybe.icl
#	Option.dcl
#	Option.icl
cat >Maybe.dcl <<'------ EOF ------'
// File   : Maybe.dcl
// Author : Richard A. O'Keefe
// Version: 1.3
// SCCS   : @(#)99/03/22 Maybe.dcl	1.3
// Defines: the (Maybe x) type, similar to (Maybe x) in Haskell
//          but with influence from ('x option) in SML.

definition module Maybe
import StdClass

:: Maybe a
 = Nothing
 | Just a

instance == (Maybe a) | == a
instance <  (Maybe a) | <  a

get_opt             :: !(Maybe a) a -> a                 // Option.getOpt
is_none             :: !(Maybe a) -> Bool                // 
is_some             :: !(Maybe a) -> Bool                // Option.isSome
opt_val             :: !(Maybe a) -> a                   // Option.valOf
none                :: (Maybe a)                         // Option.NONE
some                :: a -> *(Maybe a)                   // Option.SOME
opt_filter          :: !(a -> Bool) a -> *(Maybe a)      // Option.filter
opt_join            :: !(Maybe (Maybe a)) -> (Maybe a)   // Option.join
opt_map             :: (a -> b) !(Maybe a) -> *(Maybe b) // Option.map
opt_map_partial     :: (a -> (Maybe b)) !(Maybe a) -> (Maybe b)
opt_compose         :: (a -> b) !(c -> (Maybe a)) c -> *(Maybe b)
opt_compose_partial :: (a -> (Maybe b)) !(c -> (Maybe a)) c -> (Maybe b)
list_to_option      :: ![a] -> *(Maybe a)                // new
option_to_list      :: !(Maybe a) -> *[a]                // new
opt_flatten         :: ![!Maybe a] -> *[a]               // new

opt_map1            :: (t1 -> t)    !(Maybe t1)             -> *(Maybe t)
opt_map2            :: (t1 t2 -> t) !(Maybe t1) !(Maybe t2) -> *(Maybe t)
opt_map3            :: (t1 t2 t3 -> t)
                        !(Maybe t1) !(Maybe t2) !(Maybe t3) -> *(Maybe t)
opt_map4            :: (t1 t2 t3 t4 -> t) !(Maybe t1)
                        !(Maybe t2) !(Maybe t3) !(Maybe t4) -> *(Maybe t)

opt_map_partial1    :: (t1 -> (Maybe t))
                       !(Maybe t1) -> (Maybe t)
opt_map_partial2    :: (t1 t2 -> (Maybe t))
                       !(Maybe t1) !(Maybe t2) -> (Maybe t)
opt_map_partial3    :: (t1 t2 t3 -> (Maybe t))
                       !(Maybe t1) !(Maybe t2) !(Maybe t3) -> (Maybe t)
opt_map_partial4    :: (t1 t2 t3 t4 -> (Maybe t)) !(Maybe t1)
                       !(Maybe t2) !(Maybe t3) !(Maybe t4) -> (Maybe t)

maybe       :: a (b -> a) !(Maybe b) -> a   // Prelude.maybe
isJust      :: !(Maybe a) -> Bool           // Maybe.isJust
isNothing   :: !(Maybe a) -> Bool           // Maybe.isNothing
nothing     :: (Maybe a)                    // new
just        :: a -> *(Maybe a)              // new
fromJust    :: !(Maybe a) -> a              // Maybe.fromJust
fromMaybe   :: a !(Maybe a) -> a            // Maybe.fromMaybe
listToMaybe :: ![a] -> *(Maybe a)           // Maybe.listToMaybe
maybeToList :: !(Maybe a) -> *[a]           // Maybe.maybeToList
catMaybes   :: ![!Maybe a] -> *[a]          // Maybe.catMaybes
mapMaybe    :: !(a-> Maybe b) ![a] -> !*[b] // Maybe.mapMaybe

------ EOF ------
ls -l Maybe.dcl
cat >Maybe.icl <<'------ EOF ------'
// File   : Maybe.icl
// Author : Richard A. O'Keefe
// Version: 1.3
// SCCS   : @(#)99/03/22 Maybe.icl	1.2
// Defines: the (Maybe x) type, similar to (Maybe x) in Haskell
//          but with influence from ('x option) in SML.

implementation module Maybe
import StdClass, StdMisc

/*  When I was moving code between ML and Clean, I had an 'Option' module
    which provided the ML type and operations in Clean.
    When I had to move code between Haskell and Clean, I took the 'Option'
    module, changed the type to match Haskell, and added all the Haskell
    (Prelude,Maybe) operations as well, those that I could.

    The missing ones are
    1.  (Maybe a) isn't an instance of Read, because there is no class Read.
    2.  (Maybe a) isn't an instance of Show, because there is no class Show.
        Some way of reading and writing these things would be useful; at
        the moment there is none.  If you have something for reading or
        writing lists, use that and convert.
    3.  (Maybe a) isn't an instance of Functor, because
        a.  There is no class Functor in Clean.
        b.  The method of Functor was renamed from 'map' in Haskell 1.4
            to 'fmap' in Haskell 98.
        In the mean time, use opt_map.

    Instead of                       use
    f (Nothing) ... = e1             f m ... | isNothing m ... = e1
    f (Just x) ...  = e2             f m ... | isJust m    ... =
                                         let x = fromJust m in e2
                           
    case m of {Nothing -> e1;        if (isNothing m) (e1)
    Just x -> e2}                       (let x = fromJust m in e2)

    Nothing                          nothing
    Just x                           just x

    The functions nothing, just, some, none were provided to replace
    the constructors, so it is possible to do everything you need in
    portable code.  On the other hand, since the constructors are
    exposed in the .dcl file, you CAN use the bare constructors if you
    want to.

    I crave your forgiveness for the sickeningly ugly baStudlyCaps names
    in the latter half of this module; they truly are NOT my fault but
    are what the Haskell designers saw fit to inflict on us.
*/

:: Maybe a
 = Nothing
 | Just a


instance == (Maybe a) | == a where
    (==) :: !(Maybe a) !(Maybe a) -> Bool | == a
    (==) (Just x)  (Just y)  = x == y
    (==) (Just _)  (Nothing) = False
    (==) (Nothing) (Just _)  = False
    (==) (Nothing) (Nothing) = True


instance <  (Maybe a) | <  a where
    (<) :: !(Maybe a) !(Maybe a) -> Bool | <  a
    (<) (Nothing) (Nothing) = False
    (<) (Nothing) (Just _)  = True
    (<) (Just _)  (Nothing) = False
    (<) (Just x)  (Just y)  = x < y


/*  The following functions are copied from the SML Basis Library,
    which is why they have 'opt' in their names (from "'x option")
    even though they refer to the "Maybe" type.  Thanks to the
    fact that neither SML nor Haskell nor Clean supports abstract
    patterns, we cannot use 'SOME' as well as 'Just' and we cannot
    use 'NONE' as well as 'Nothing'.  That's why we have an Option
    type (in Option.icl) as well as a Maybe type; it's not expected
    that both of them will be used in one program, but it should be
    a bit easier to port code in one direction or the other.
*/

// get_opt x default
// returns default if x is missing, or the content of x if that is present.

get_opt :: !(Maybe a) a -> a                // see fromMaybe
get_opt (Nothing) x = x
get_opt (Just x)  _ = x


is_none :: !(Maybe a) -> Bool                // see isNothing
is_none (Nothing) = True
is_none (Just _)  = False


is_some :: !(Maybe a) -> Bool                // see isJust
is_some (Nothing) = False
is_some (Just _)  = True


opt_val :: !(Maybe a) -> a                   // see fromJust
opt_val (Nothing) = abort "Maybe.opt_val: Nothing"
opt_val (Just x)  = x


none :: (Maybe a)                           // see nothing
none = Nothing


some :: a -> *(Maybe a)                     // see just
some x = Just x


opt_filter :: !(a -> Bool) a -> *(Maybe a)
opt_filter f a | f a = Just a
opt_filter _ _       = Nothing


opt_join :: !(Maybe (Maybe a)) -> (Maybe a)
opt_join (Just v) = v
opt_join _        = Nothing


opt_map :: (a -> b) !(Maybe a) -> *(Maybe b)
opt_map f (Nothing) = Nothing
opt_map f (Just x)  = Just (f x)

opt_map1 :: (t1 -> t)
           !(Maybe t1)
         -> *(Maybe t)
opt_map1 f (Just x1) = Just (f x1)
opt_map1 _ _         = Nothing

opt_map2 :: (t1 t2 -> t)
           !(Maybe t1) !(Maybe t2)
         -> *(Maybe t)
opt_map2 f (Just x1) (Just x2) = Just (f x1 x2)
opt_map2 f _         _         = Nothing

opt_map3 :: (t1 t2 t3 -> t)
           !(Maybe t1) !(Maybe t2) !(Maybe t3)
         -> *(Maybe t)
opt_map3 f (Just x1) (Just x2) (Just x3) = Just (f x1 x2 x3)
opt_map3 _ _         _         _         = Nothing

opt_map4 :: (t1 t2 t3 t4 -> t)
           !(Maybe t1) !(Maybe t2) !(Maybe t3) !(Maybe t4)
         -> *(Maybe t)
opt_map4 f (Just x1) (Just x2) (Just x3) (Just x4) = Just (f x1 x2 x3 x4)
opt_map4 _ _         _         _         _         = Nothing


opt_map_partial :: (a -> (Maybe b)) !(Maybe a) -> (Maybe b)
opt_map_partial f (Nothing) = Nothing
opt_map_partial f (Just x)  = f x

opt_map_partial1 :: (t1 -> (Maybe t))
                   !(Maybe t1)
                 -> (Maybe t)
opt_map_partial1 f (Just x1) = f x1
opt_map_partial1 _ _         = Nothing

opt_map_partial2 :: (t1 t2 -> (Maybe t))
                   !(Maybe t1) !(Maybe t2)
                 -> (Maybe t)
opt_map_partial2 f (Just x1) (Just x2) = f x1 x2
opt_map_partial2 f _         _         = Nothing

opt_map_partial3 :: (t1 t2 t3 -> (Maybe t))
                   !(Maybe t1) !(Maybe t2) !(Maybe t3)
                 -> (Maybe t)
opt_map_partial3 f (Just x1) (Just x2) (Just x3) = f x1 x2 x3
opt_map_partial3 _ _         _         _         = Nothing

opt_map_partial4 :: (t1 t2 t3 t4 -> (Maybe t))
                   !(Maybe t1) !(Maybe t2) !(Maybe t3) !(Maybe t4)
                 -> (Maybe t)
opt_map_partial4 f (Just x1) (Just x2) (Just x3) (Just x4) = f x1 x2 x3 x4
opt_map_partial4 _ _         _         _         _         = Nothing


opt_compose :: (a -> b) !(c -> (Maybe a)) c -> *(Maybe b)
opt_compose f g x =
  case g x of
    Nothing -> Nothing
    Just y  -> Just (f y)


opt_compose_partial :: (a -> (Maybe b)) !(c -> (Maybe a)) c -> (Maybe b)
opt_compose_partial f g x =
  case g x of
    Nothing -> Nothing
    Just y  -> f y


opt_flatten :: ![!Maybe t] -> *[t]         // see catMaybes
opt_flatten []          = []
opt_flatten [Nothing:xs] =    opt_flatten xs
opt_flatten [Just x :xs] = [x:opt_flatten xs]


list_to_option :: ![a] -> *(Maybe a)       // see listToMaybe
list_to_option []    = Nothing
list_to_option [x:_] = Just x


option_to_list :: !(Maybe a) -> *[a]       // see maybeToList
option_to_list (Nothing) = []
option_to_list (Just x)  = [x]


/*  The following functions are copied from the Haskell library.
    Note that thanks to the Haskell 1.4/Haskell 98 transition,
    Functor is still a bit dodgy, so don't expect _either_ "map"
    _or_ "fmap" to work on maybes yet.  Use opt_map instead.

    The Monad, MonadPlus, and MonadZero classes are not currently
    set up because they aren't commonly used in Clean.

    The Show and Read classes are not set up because they do not
    exist in Clean, more's the pity.

    I entreat your forgiveness for the despicable baStudlyCaps names,
    but it really truly isn't my fault (except isNothing); these are
    the names the Haskell developers have inflicted on us.

    isNothing is not in fact in the Haskell library but it should be.


*/

// maybe default f x = get_opt (opt_map f x) default

maybe :: a (b -> a) !(Maybe b) -> a
maybe d _ (Nothing) = d
maybe _ f (Just x)  = f x


isJust :: !(Maybe a) -> Bool                // see is_some
isJust (Nothing) = False
isJust (Just _)  = True


isNothing :: !(Maybe a) -> Bool             // see is_none
isNothing (Nothing) = True
isNothing (Just _)  = False


nothing :: (Maybe a)                        // see none
nothing = Nothing


just :: a -> *(Maybe a)                     // see some
just x = Just x


fromJust :: !(Maybe a) -> a                 // see opt_val
fromJust (Nothing) = abort "Maybe.fromJust: Nothing"
fromJust (Just x)  = x


fromMaybe :: a !(Maybe a) -> a              // see get_opt
fromMaybe d (Nothing) = d
fromMaybe _ (Just x)  = x


listToMaybe :: ![a] -> *(Maybe a)          // see list_to_option
listToMaybe []    = Nothing
listToMaybe [x:_] = Just x
 

maybeToList :: !(Maybe a) -> *[a]         // see option_to_list
maybeToList (Nothing) = []
maybeToList (Just x)  = [x]


catMaybes :: ![!Maybe a] -> *[a]         // see opt_flatten
catMaybes [Nothing:xs] =    catMaybes xs
catMaybes [Just x :xs] = [x:catMaybes xs]
catMaybes []          = []


mapMaybe :: !(a -> Maybe b) ![a] -> !*[b]
mapMaybe f [x:xs] = case f x of
                     Nothing -> mapMaybe f xs
                     Just y  -> [y:mapMaybe f xs]
mapMaybe _ f      = []

------ EOF ------
ls -l Maybe.icl
cat >Option.dcl <<'------ EOF ------'
// File   : Option.dcl
// Author : Richard A. O'Keefe
// Version: 1.3
// SCCS   : @(#)99/03/22 Option.dcl	1.1
// Defines: the (Option x) type, similar to (Maybe x) in Haskell
//          but with influence from ('x option) in SML.

definition module Option
import StdClass

:: Option a
 = NONE
 | SOME a

instance == (Option a) | == a
instance <  (Option a) | <  a

get_opt             :: !(Option a) a -> a                 // Option.getOpt
is_none             :: !(Option a) -> Bool                // 
is_some             :: !(Option a) -> Bool                // Option.isSome
opt_val             :: !(Option a) -> a                   // Option.valOf
none                :: (Option a)                         // Option.NONE
some                :: a -> *(Option a)                   // Option.SOME
opt_filter          :: !(a -> Bool) a -> *(Option a)      // Option.filter
opt_join            :: !(Option (Option a)) -> (Option a)   // Option.join
opt_map             :: (a -> b) !(Option a) -> *(Option b) // Option.map
opt_map_partial     :: (a -> (Option b)) !(Option a) -> (Option b)
opt_compose         :: (a -> b) !(c -> (Option a)) c -> *(Option b)
opt_compose_partial :: (a -> (Option b)) !(c -> (Option a)) c -> (Option b)
list_to_option      :: ![a] -> *(Option a)                // new
option_to_list      :: !(Option a) -> *[a]                // new
opt_flatten         :: ![!Option a] -> *[a]               // new

opt_map1            :: (t1 -> t)    !(Option t1)             -> *(Option t)
opt_map2            :: (t1 t2 -> t) !(Option t1) !(Option t2) -> *(Option t)
opt_map3            :: (t1 t2 t3 -> t)
                        !(Option t1) !(Option t2) !(Option t3) -> *(Option t)
opt_map4            :: (t1 t2 t3 t4 -> t) !(Option t1)
                        !(Option t2) !(Option t3) !(Option t4) -> *(Option t)

opt_map_partial1    :: (t1 -> (Option t))
                       !(Option t1) -> (Option t)
opt_map_partial2    :: (t1 t2 -> (Option t))
                       !(Option t1) !(Option t2) -> (Option t)
opt_map_partial3    :: (t1 t2 t3 -> (Option t))
                       !(Option t1) !(Option t2) !(Option t3) -> (Option t)
opt_map_partial4    :: (t1 t2 t3 t4 -> (Option t)) !(Option t1)
                       !(Option t2) !(Option t3) !(Option t4) -> (Option t)

maybe       :: a (b -> a) !(Option b) -> a   // Prelude.maybe
isJust      :: !(Option a) -> Bool           // Maybe.isJust
isNothing   :: !(Option a) -> Bool           // Maybe.isNothing
nothing     :: (Option a)                    // new
just        :: a -> *(Option a)              // new
fromJust    :: !(Option a) -> a              // Maybe.fromJust
fromMaybe   :: a !(Option a) -> a            // Maybe.fromMaybe
listToMaybe :: ![a] -> *(Option a)           // Maybe.listToMaybe
maybeToList :: !(Option a) -> *[a]           // Maybe.maybeToList
catMaybes   :: ![!Option a] -> *[a]          // Maybe.catMaybes
mapMaybe    :: !(a-> Option b) ![a] -> !*[b] // Maybe.mapMaybe

------ EOF ------
ls -l Option.dcl
cat >Option.icl <<'------ EOF ------'
// File   : Option.icl
// Author : Richard A. O'Keefe
// Version: 1.3
// SCCS   : @(#)99/03/22 Option.icl	1.1
// Defines: the (Option x) type, similar to (Maybe x) in Haskell
//          but with influence from ('x option) in SML.

implementation module Option
import StdClass, StdMisc

/*  When I was moving code between ML and Clean, I had an 'Option' module
    which provided the ML type and operations in Clean.
    When I had to move code between Haskell and Clean, I took the 'Option'
    module, changed the type to match Haskell, and added all the Haskell
    (Prelude,Maybe) operations as well, those that I could.

    The missing ones are
    1.  (Option a) isn't an instance of Read, because there is no class Read.
    2.  (Option a) isn't an instance of Show, because there is no class Show.
        Some way of reading and writing these things would be useful; at
        the moment there is none.  If you have something for reading or
        writing lists, use that and convert.
    3.  (Option a) isn't an instance of Functor, because
        a.  There is no class Functor in Clean.
        b.  The method of Functor was renamed from 'map' in Haskell 1.4
            to 'fmap' in Haskell 98.
        In the mean time, use opt_map.

    Instead of                    use
    f (NONE) ... = e1             f m ... | is_none m ... = e1
    f (SOME x) ...  = e2             f m ... | is_some m    ... =
                                         let x = opt_val m in e2
                           
    case m of {NONE -> e1;        if (is_none m) (e1)
    SOME x -> e2}                    (let x = opt_val m in e2)

    NONE                          none
    SOME x                        some x

    The functions nothing, just, some, none were provided to replace
    the constructors, so it is possible to do everything you need in
    portable code.  On the other hand, since the constructors are
    exposed in the .dcl file, you CAN use the bare constructors if you
    want to.

    I crave your forgiveness for the sickeningly ugly baStudlyCaps names
    in the latter half of this module; they truly are NOT my fault but
    are what the Haskell designers saw fit to inflict on us.
*/

:: Option a
 = NONE
 | SOME a


instance == (Option a) | == a where
    (==) :: !(Option a) !(Option a) -> Bool | == a
    (==) (SOME x) (SOME y) = x == y
    (==) (SOME _) (NONE)   = False
    (==) (NONE)   (SOME _) = False
    (==) (NONE)   (NONE)   = True


instance <  (Option a) | <  a where
    (<) :: !(Option a) !(Option a) -> Bool | <  a
    (<) (NONE)   (NONE)   = False
    (<) (NONE)   (SOME _) = True
    (<) (SOME _) (NONE)   = False
    (<) (SOME x) (SOME y) = x < y


/*  The following functions are copied from the SML Basis Library,
    which is why they have 'opt' in their names (from "'x option").
    Since moving between SML and (Haskell or Clean) is not as trivial
    as moving between Haskell and Clean, I felt that it would be s
    small additional burden to do something about those sickeningly
    horrible baStudlyCaps names (like Option.valOf) and the somewhat
    inconsistent argument style.  Thanks to the
    fact that neither SML nor Haskell nor Clean supports abstract
    patterns, we cannot use 'Just' as well as 'SOME' and we cannot
    use 'Nothing' as well as 'NONE'.  That's why we have a Maybe
    type (in Maybe.icl) as well as an Option type; it's not expected
    that both of them will be used in one program, but it should be
    a bit easier to port code in one direction or the other.

    It is arguable that the ML-like names should be exactly the same
    as the ML ones, loathesome though they are, and if enough people
    complained I would make that switch.  However, it seemed better to
    me to provide a maybe.sml instead...
*/

// get_opt x default
// returns default if x is missing, or the content of x if that is present.

get_opt :: !(Option a) a -> a                // see fromMaybe
get_opt (NONE)   x = x
get_opt (SOME x) _ = x


is_none :: !(Option a) -> Bool                // see isNothing
is_none (NONE)   = True
is_none (SOME _) = False


is_some :: !(Option a) -> Bool                // see isJust
is_some (NONE)   = False
is_some (SOME _) = True


opt_val :: !(Option a) -> a                   // see fromJust
opt_val (NONE)   = abort "Option.opt_val: NONE"
opt_val (SOME x) = x


none :: (Option a)                           // see nothing
none = NONE


some :: a -> *(Option a)                     // see just
some x = SOME x


opt_filter :: !(a -> Bool) a -> *(Option a)
opt_filter f a | f a = SOME a
opt_filter _ _       = NONE


opt_join :: !(Option (Option a)) -> (Option a)
opt_join (SOME v) = v
opt_join _        = NONE


opt_map :: (a -> b) !(Option a) -> *(Option b)
opt_map f (NONE)   = NONE
opt_map f (SOME x) = SOME (f x)

opt_map1 :: (t1 -> t)
           !(Option t1)
         -> *(Option t)
opt_map1 f (SOME x1) = SOME (f x1)
opt_map1 _ _         = NONE

opt_map2 :: (t1 t2 -> t)
           !(Option t1) !(Option t2)
         -> *(Option t)
opt_map2 f (SOME x1) (SOME x2) = SOME (f x1 x2)
opt_map2 f _         _         = NONE

opt_map3 :: (t1 t2 t3 -> t)
           !(Option t1) !(Option t2) !(Option t3)
         -> *(Option t)
opt_map3 f (SOME x1) (SOME x2) (SOME x3) = SOME (f x1 x2 x3)
opt_map3 _ _         _         _         = NONE

opt_map4 :: (t1 t2 t3 t4 -> t)
           !(Option t1) !(Option t2) !(Option t3) !(Option t4)
         -> *(Option t)
opt_map4 f (SOME x1) (SOME x2) (SOME x3) (SOME x4) = SOME (f x1 x2 x3 x4)
opt_map4 _ _         _         _         _         = NONE


opt_map_partial :: (a -> (Option b)) !(Option a) -> (Option b)
opt_map_partial f (NONE)   = NONE
opt_map_partial f (SOME x) = f x

opt_map_partial1 :: (t1 -> (Option t))
                   !(Option t1)
                 -> (Option t)
opt_map_partial1 f (SOME x1) = f x1
opt_map_partial1 _ _         = NONE

opt_map_partial2 :: (t1 t2 -> (Option t))
                   !(Option t1) !(Option t2)
                 -> (Option t)
opt_map_partial2 f (SOME x1) (SOME x2) = f x1 x2
opt_map_partial2 f _         _         = NONE

opt_map_partial3 :: (t1 t2 t3 -> (Option t))
                   !(Option t1) !(Option t2) !(Option t3)
                 -> (Option t)
opt_map_partial3 f (SOME x1) (SOME x2) (SOME x3) = f x1 x2 x3
opt_map_partial3 _ _         _         _         = NONE

opt_map_partial4 :: (t1 t2 t3 t4 -> (Option t))
                   !(Option t1) !(Option t2) !(Option t3) !(Option t4)
                 -> (Option t)
opt_map_partial4 f (SOME x1) (SOME x2) (SOME x3) (SOME x4) = f x1 x2 x3 x4
opt_map_partial4 _ _         _         _         _         = NONE


opt_compose :: (a -> b) !(c -> (Option a)) c -> *(Option b)
opt_compose f g x =
  case g x of
    NONE   -> NONE
    SOME y -> SOME (f y)


opt_compose_partial :: (a -> (Option b)) !(c -> (Option a)) c -> (Option b)
opt_compose_partial f g x =
  case g x of
    NONE   -> NONE
    SOME y -> f y


opt_flatten :: ![!Option t] -> *[t]         // see catMaybes
opt_flatten []          = []
opt_flatten [NONE  :xs] =    opt_flatten xs
opt_flatten [SOME x:xs] = [x:opt_flatten xs]


list_to_option :: ![a] -> *(Option a)       // see listToMaybe
list_to_option []    = NONE
list_to_option [x:_] = SOME x


option_to_list :: !(Option a) -> *[a]       // see maybeToList
option_to_list (NONE)   = []
option_to_list (SOME x) = [x]


/*  The following functions are copied from the Haskell library.
    Note that thanks to the Haskell 1.4/Haskell 98 transition,
    Functor is still a bit dodgy, so don't expect _either_ "map"
    _or_ "fmap" to work on maybes yet.  Use opt_map instead.

    The Monad, MonadPlus, and MonadZero classes are not currently
    set up because they aren't commonly used in Clean.

    The Show and Read classes are not set up because they do not
    exist in Clean, more's the pity.

    I entreat your forgiveness for the despicable baStudlyCaps names,
    but it really truly isn't my fault (except isNothing); these are
    the names the Haskell developers have inflicted on us.

    isNothing is not in fact in the Haskell library but it should be.


*/

// maybe default f x = get_opt (opt_map f x) default

maybe :: a (b -> a) !(Option b) -> a
maybe d _ (NONE)   = d
maybe _ f (SOME x) = f x


isJust :: !(Option a) -> Bool                // see is_some
isJust (NONE)   = False
isJust (SOME _) = True


isNothing :: !(Option a) -> Bool             // see is_none
isNothing (NONE)   = True
isNothing (SOME _) = False


nothing :: (Option a)                        // see none
nothing = NONE


just :: a -> *(Option a)                     // see some
just x = SOME x


fromJust :: !(Option a) -> a                 // see opt_val
fromJust (NONE)   = abort "Option.fromJust: NONE"
fromJust (SOME x) = x


fromMaybe :: a !(Option a) -> a              // see get_opt
fromMaybe d (NONE)   = d
fromMaybe _ (SOME x) = x


listToMaybe :: ![a] -> *(Option a)          // see list_to_option
listToMaybe []    = NONE
listToMaybe [x:_] = SOME x
 

maybeToList :: !(Option a) -> *[a]         // see option_to_list
maybeToList (NONE)   = []
maybeToList (SOME x) = [x]


catMaybes :: ![!Option a] -> *[a]         // see opt_flatten
catMaybes [NONE  :xs] =    catMaybes xs
catMaybes [SOME x:xs] = [x:catMaybes xs]
catMaybes []          = []


mapMaybe :: !(a -> Option b) ![a] -> !*[b]
mapMaybe f [x:xs] = case f x of
                     NONE   -> mapMaybe f xs
                     SOME y -> [y:mapMaybe f xs]
mapMaybe _ f      = []

------ EOF ------
ls -l Option.icl