case classesval)- case class C (x:Int, y:String)
- val c:C = C (5, "hello")
- val a:Int = c.x
- c.x = 6 // error: reassignment to val
toString implementationapply method
unapply method / extractors in textbookenum similar to Java interface- enum Node:
- case Val(val x: Int)
- case Op(val l: Node, r: Node, val f: (Int, Int)=>Int)
- val three = Val(3)
- val op = Op(three, Val(5), _ + _)
- def eval(node: Node) : Int = node match
- case Val(x) => x
- case Op(l, r) => f(eval(l), eval(r))
- // (3+5)*2
- eval(Op(Op(Val(3), Val(5), _ + _), Val(2), _ * _))
- struct s_val_t;
- struct s_op_t;
- union u_node_t {
- struct s_val_t* u_val;
- struct s_op_t* u_op;
- };
- struct s_val_t { int x; };
- struct s_op_t {
- struct u_node_t l;
- struct u_node_t r;
- int (*op)(int,int);
- };
u_node_t?- enum e_node_t {
- e_val,
- e_op,
- };
- struct node_t {
- enum e_node_t tag;
- union u_node_t content;
- };
- struct s_op_t {
- struct node_t l;
- struct node_t r;
- int (*op)(int,int);
- };
- int add(int x, int y) { return x+y; }
- struct s_val_t three = { .x=3 };
- struct s_val_t five = { .x=5 };
- struct s_op_t op = {
- .l = {
- .tag = e_val,
- .content = { .u_val = &three }
- },
- .r = {
- .tag = e_val,
- .content = { .u_val = &five }
- },
- .op = &add
- };
- struct node_t node = {
- .tag = e_op,
- .content = { .u_op = &op }
- };
- int eval (struct node_t* node) {
- switch (node->tag) {
- case e_val:
- return node->content.u_val->x;
- case e_op: {
- struct s_op_t* o = node->content.u_op;
- return o->op(eval(&o->l), eval(&o->r));
- }
- default:
- fprintf (stderr, "Unknown tag\n");
- exit (1);
- }
- }
PeanoNat- enum PeanoNat:
- case Zero
- case Succ (n:PeanoNat)
PeanoNat and Int- def peano2int (p:PeanoNat, result: Int = 0): Int = p match
- case PeanoNat.Zero => result
- case PeanoNat.Succ(n) => peano2int (n, result+1)
- import PeanoNat.*
- val q = Succ (Succ (Succ (Zero))) // : Peano = ...
- peano2int (q) // : Int = 3
Which case classes and case objects?
Empty list and a Cons cell of at least one element- enum MyList:
- case Empty
- case Cons (head:Int, tail:MyList)
- enum MyList:
- case Empty
- case Cons (head:Int, tail:MyList)
Create an empty list?
Simply use Empty
- import MyList.*
- val xs = Empty
Create an instance of a list?
Nest Cons and terminate with Empty
- import MyList.*
- val xs = Cons (1, Cons(2, Cons(3, Empty)))
- enum MyList:
- case Empty
- case Cons (head:Int, tail:MyList)
- object MyList:
- def create(elems: Int*) =
- elems.foldRight(Empty)((e, l) => Cons(e, l))
Create an instance of a list?
Use method create
- import MyList.*
- // val xs = Cons (1, Cons(2, Cons(3, Empty)))
- val xs = MyList.create(1, 2, 3)
Generalize to any element type?
- enum MyList[+X]:
- case Empty
- case Cons (head:X, tail:MyList[X])
Compute the length of such a list?
- def length [X] (xs:MyList[X]): Int = xs match
- case MyList.Empty => 0
- case MyList.Cons(a,as) => 1 + length(as)
- def length [X] (xs:MyList[X], result:Int = 0): Int = xs match
- case MyList.Empty => result
- case MyList.Cons(a,as) => length(as, result+1)
- enum Tree[X]:
- case Leaf (data:X)
- case Node (l:Tree[X], f:(X,X)=>X, r:Tree[X])
Fold tree into result by applying all the intermediate operations
Recursive with pattern matching
- def fold [X] (t: Tree[X]) : X = t match
- case Leaf(x) => x
- case Node(l, f, r) => f(fold(l), fold(r))
enum and case classes