use std trait bindable @t -> @a, @b = bind : (b : @t, f : (a : @a -> @b) -> @b) ;; trait bindable1 @a -> @f, @b = bind1 : (a : @a, f : @f -> @b) ;; trait bindable2 @a -> @f = bind2 : (a : @a, f : @f -> @a) ;; impl bindable std.option(@a) -> @a, std.option(@b) = bind = {o, f match o | `std.Some v: -> f(v) | `std.None: -> `std.None ;; } ;; impl bindable1 std.option(@a) -> (a : @a -> std.option(@b)), std.option(@b) = bind1 = {o, f match o | `std.Some v: -> f(v) | `std.None: -> `std.None ;; } ;; impl bindable2 std.option(@a) -> (a : @a -> std.option(@a)) = bind2 = {o, f match o | `std.Some v: -> f(v) | `std.None: -> `std.None ;; } ;; generic bind3 = {o, f match o | `std.Some v: -> f(v) | `std.None: -> `std.None ;; } const gets = {n if n == 0 -> `std.Some "hello" ;; -> `std.None } const append = {s if s.len < 16 -> `std.Some std.strcat(s, " world") ;; -> `std.None } const put = {o match o | `std.Some s: std.put("{}\n", s) | `std.None: ;; } const main = { // put(bind(gets(std.rand(0, 1)), append)) // put(bind1(gets(std.rand(0, 1)), append)) // put(bind2(gets(std.rand(0, 1)), append)) put(bind3(gets(std.rand(0, 1)), append)) put(bind3(bind3(gets(std.rand(0, 1)), append), append)) put(bind3(bind3(bind3(gets(std.rand(0, 1)), append), append), append)) }