(* ****** ****** *)
#include
"share/atspre_define.hats"
#include
"share/atspre_staload.hats"
(* ****** ****** *)
// the interface
abst@ype M (t@ype) = ptr
extern
fun{a:t@ype}
ret : a -> M(a)
extern
fun{a,b:t@ype}
bind : M(a) -> M(b)
symintr >>=
postfix >>=
overload >>= with bind
// we replace the second argument of bind with a function template
// which should allow the ATS compiler to inline aggressively
extern
fun{a,b:t@ype}
bind$cont (x: a): M(b)
(* ****** ****** *)
extern
fun{a,b:t@ype}
bind1 : M(a) -> M(b)
extern
fun{a,b:t@ype}
bind2 : M(a) -> M(b)
(* ****** ****** *)
// one possible implementation
assume M (a:t@ype) = Option a
// an explicit failure function (cf. MonadFail)
fun Mfail {a:t@ype} (): M(a) = None ()
implement
{a}(*tmp*)
ret (x) = Some x
implement
{a,b}
bind (x) = let
//
val () = println! ("bind: x = ...")
//
in
//
case+ x of
| Some x => bind$cont<a,b>(x) | None () => None ()
//
end // end of [bind]
(* ****** ****** *)
implement
{a,b}
bind1 (x) = let
//
val () = println! ("bind1: x = ...")
//
in
//
case+ x of
| Some x => bind$cont<a,b>(x) | None () => None ()
//
end // end of [bind1]
(* ****** ****** *)
implement
{a,b}
bind2 (x) = let
//
val () = println! ("bind2: x = ...")
//
in
//
case+ x of
| Some x => bind$cont<a,b>(x) | None () => None ()
//
end // end of [bind2]
(* ****** ****** *)
// a Maybe monad can be run
fun{a:t@ype} runM (x : M(a)): a =
case+ x of
| Some x => x
| None () => exit_errmsg (1, "runM failed!")
(* ****** ****** *)
(*
// usage example
// this computation doesn't know anything about the internals
// of the implementation of the underlying monad, I think
fun test (x : int): M int =
ret 5 >>= where {implement bind$cont<int,int> (y) =
ret 4 >>= where {implement bind$cont<int,int> (z) =
ret (x + y + z)}}
*)
(*
fun test (x : int): M int =
bind<int,int>(ret(5)) where {implement bind$cont<int,int> (y) =
bind<int,int>(ret(4)) where {implement bind$cont<int,int> (z) =
ret (x + y + z)}}
*)
(*
fun test (x : int): M int = ret(x)
*)
(*
fun
test (x : int): M int =
bind<int,int>(ret(10)) where
{
implement bind$cont<int,int> (y) = ret (x + y)
}
*)
fun
test
(
x : int
) : M int = let
//
implement
bind$cont<int,int> (y) = let
//
val () = println! ("bind$cont(1): y = ", y)
//
implement
bind$cont<int,int> (z) = let
//
val () = println! ("bind$cont: 2") in ret (x + y + z)
//
end // end of [bind$cont]
//
in
bind1<int,int> (ret(10))
end // end of [bind$cont]
//
in
bind2<int,int> (ret(100))
end // end of [test]
(* ****** ****** *)
implement
main0 (argc, argv) = let
val comp = test (argc)
// specify the type explicitly
val res = runM<int> (comp)
in
println!("result = ", res);
end // end of [main]
(* ****** ****** *)