[MLton-user] Wish for a standard sum type

Jesper Louis Andersen jlouis@mongers.org
Thu, 01 Jun 2006 19:56:16 +0200


On Sun, 2006-05-28 at 14:41 +0300, Vesa Karvonen wrote:

The best version I can come up with is something along the lines of:

signature ALTERNATE =
sig
    type ('a, 'b) t

    exception SumMismatchException

    val inl : 'a -> ('a, 'b) t
    val inr : 'b -> ('a, 'b) t

    val isl : ('a, 'b) t -> bool
    val isr : ('a, 'b) t -> bool

    val outl : ('a, 'b) t -> 'a
    val outr : ('a, 'b) t -> 'b

    val alternate : ('a -> 'c) * ('b -> 'c) -> ('a, 'b) t -> 'c
    val parallel  : ('a -> 'c) * ('b -> 'd) -> ('a, 'b) t -> ('c, 'd) t
end

structure Alternate :> ALTERNATE =
struct
  datatype ('a, 'b) t = INL of 'a
                      | INR of 'b

  exception SumMismatchException

  fun inl x = INL x
  fun inr x = INR x

  fun isl x = case x of
                INL _ => true
              | INR _ => false
 
  fun isr x = (not o isl) x

  fun outl x = case x of
                 INL x => x
               | INR _ => raise SumMismatchException

  fun outr x = case x of
                 INL _ => raise SumMismatchException
               | INR x => x 

  fun alternate (f, g) x = case x of
                             INL a => f a
                           | INR b => g b

  fun parallel (f, g) x = case x of
                            INL a => INL (f a)
                          | INR b => INR (g b)
end

structure TestAlternate =
struct

  open Alternate

  val testcase1 = 1 = (outl o inl) 1
  val testcase2 = 1 = (outr o inr) 1
  val testcase3 = isl (inl 1) = true
  val testcase4 = isr (inl 1) = false
  val testcase5 = let fun join x = alternate (fn x => 1, fn x => 2) x
                  in 4 = (join(inl 1) + join(inr 1) + join(inl 1))
                  end
  val testcase6 = let fun par x = parallel (fn x => x + 1, fn x => x +
2) x
                  in 8 = outl (par (inl 1)) + outr (par (inr 4))
                  end

		   

end

Do I miss any kind of operations which are obviously defineable for an
Alternate type. I did also discuss, quickly, the naming of the type with
Andrzej Filinski, who preferred INL, INR or IN1, IN2, ...,INn. His good
reason to reject FST and SND was that fst and snd are defined on A * B
(the product composition on types) rather than A + B (the sum
composition), technical or not, heh.

In Haskell, The Data.Either type, defined more or less as above, was
historically used to encode errors (think exceptions) via manual
explicit passing of the type. INR, was the "right" value, so it was used
as the succesful injection, whereas the "left" value was used for
failure. Being Haskell, the pun was intended.

I assume it is generally known to this audience that the sum data type
obeys the monad laws and can be used to implement exceptions in a nice
way in purely functional programming. 

It _is_ useable in other cases. I view it as an data-equivalent of an
if..then..else.. control-construct. Sometimes there are 2 outcomes,
which are not easily writeable with a if-then-else block. In that case,
it might be to your advantage to pass it via the data rather than via
control.

Just my 2 cents on the Alternate.