10. Typeclasses

Felix has typeclasses similar to Haskell.
Start felix section to tut/tutorial/tut-9-0.flx[1 /1 ]
     1: #line 6035 "./lpsrc/flx_tutorial.pak"
     2: //Check typeclasses
     3: #import <flx.flxh>
     4: 
     5: typeclass XStr[T] {
     6:   virtual fun str2: T->string;
     7: }
     8: 
     9: instance XStr[int] {
    10:   fun str2 (x:int):string => str x;
    11: }
    12: 
    13: open List;
    14: 
    15: fun foo[T with XStr[T]] (x:list[T]):string =>
    16:   match x with
    17:   | Empty[T] => "()"
    18:   | Cons(?h, ?t) => "(" + (str2 h) + ", " + (foo t) + ")"
    19:   endmatch
    20: ;
    21: 
    22: val x = list(1,2);
    23: print$ foo x; endl;
End felix section to tut/tutorial/tut-9-0.flx[1]
Start data section to tut/tutorial/tut-9-0.expect[1 /1 ]
     1: (1, (2, ()))
End data section to tut/tutorial/tut-9-0.expect[1]
in a module:
Start felix section to tut/tutorial/tut-9-1.flx[1 /1 ]
     1: #line 6064 "./lpsrc/flx_tutorial.pak"
     2: //Check typeclasses
     3: #import <flx.flxh>
     4: 
     5: open List;
     6: 
     7: typeclass XStr[T] {
     8:   virtual fun str2: T->string;
     9: }
    10: 
    11: module Foo {
    12:   instance XStr[int] {
    13:     fun str2 (x:int):string => str x;
    14:   }
    15: 
    16:   fun foo[T with XStr[T]] (x:T):string => str2 x;
    17: 
    18:   fun foo[T with XStr[T]] (x:list[T]):string =>
    19:     match x with
    20:     | Empty[T] => "()"
    21:     | Cons(?h, ?t) => "(" + (str2 h) + ", " + (foo t) + ")"
    22:     endmatch
    23:   ;
    24: }
    25: 
    26: open Foo;
    27: 
    28: print$ Foo::foo 5; endl;
    29: print$ Foo::foo$ list(1,2,3,4); endl;
    30: 
End felix section to tut/tutorial/tut-9-1.flx[1]
Start data section to tut/tutorial/tut-9-1.expect[1 /1 ]
     1: 5
     2: (1, (2, (3, (4, ()))))
End data section to tut/tutorial/tut-9-1.expect[1]
Start felix section to tut/tutorial/tut-9-2.flx[1 /1 ]
     1: #line 6099 "./lpsrc/flx_tutorial.pak"
     2: //Check typeclasses:monad
     3: #import <flx.flxh>
     4: 
     5: typedef fun Maybe (t:TYPE):TYPE=>opt[t];
     6: 
     7: instance Monad [the Maybe] {
     8:   fun bind[a,b] (x:Maybe a, f:a -> Maybe b) =>
     9:     match x with
    10:     | None[a] => None[b]
    11:     | Some ?x => f x
    12:     endmatch
    13:   ;
    14: 
    15:   fun ret[a](x:a):Maybe a => Some x;
    16: }
    17: 
    18: fun madd(x:double) (y:double):opt[double]=>Some (y+x);
    19: fun msub(x:double) (y:double):opt[double]=>Some (y-x);
    20: fun mmul(x:double) (y:double):opt[double]=>Some (y*x);
    21: fun mdiv(x:double) (y:double):opt[double]=>
    22:   if x == 0.0 then None[double] else Some (y/x) endif
    23: ;
    24: fun mneg(x:double):opt[double]=>Some (-x);
    25: 
    26: open Monad[the Maybe];
    27: 
    28: proc show(r:Maybe double) {
    29:    match r with
    30:   | Some ?x => { print x; }
    31:   | None => { print "divide by zero somewhere"; }
    32:   endmatch; endl;
    33: }
    34: 
    35: // we have to put this here so it overrides left shift assignment operator
    36: #infix 10 ">>=" bind
    37: 
    38: var x1 = 2.7; var y1 = 1.2; var z = 0.0;
    39: {
    40:   var r = ret x1 >>= msub y1 >>= mdiv z;
    41:   show r;
    42: };
    43: 
    44: {
    45:   var r = ret x1 >>= msub y1 >>= mdiv 2.0;
    46:   show r;
    47: };
End felix section to tut/tutorial/tut-9-2.flx[1]
Start data section to tut/tutorial/tut-9-2.expect[1 /1 ]
     1: divide by zero somewhere
     2: 0.75
End data section to tut/tutorial/tut-9-2.expect[1]