Sunday, 6 May 2012

Refactor your union types to simplify common operations


Perhaps the most common example of this problem arising in practice is in operators:
type expr =
  | Add of expr * expr
  | Sub of expr * expr
  | Mul of expr * expr
  | Div of expr * expr
  | Pow of expr * expr
  | ...
where you might restructure your type as follows:
type binOp = Add | Sub | Mul | Div | Pow
type expr =
  | BinOp of binOp * expr * expr
  | ...
Then tasks like extracting subexpressions:
let subExprs = function
  | Add(f, g)
  | Sub(f, g)
  | Mul(f, g)
  | Div(f, g)
  | Pow(f, g) -> [f; g]
  | ...
can be performed more easily:
let subExprs = function
  | BinOp(_, f, g) -> [f; g]
  | ...
Finally, don't forget that you can augment F# types (such as union types) with OOP constructs such as implementing shared interfaces. This can also be used to express commonality, e.g. if you have two overlapping requirements on two types then you might make them both implement the same interface in order to expose this commonality.

No comments: