[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.