153 lines · 4.3 KB · Standard ML
RawDownload
(* Example: implementing polynomials using higher-order functors *) (* the signature of structures implementing natural numbers *)  signature NAT =     sig type nat	val z:nat                         (* zero *)	val s:nat->nat                    (* successor *)	val i:'a -> ('a->'a) -> nat -> 'a (* iteration *)    end; (* the signature of structures evaluating polynomials,   presented as a list of coefficients    eg      eval x [c0,...,cn] = (c0 * x^0) + .... + (cn * x^n)*) signature POLY =   sig structure Nat:NAT;       val eval:Nat.nat->(Nat.nat list)->Nat.nat;  end; (* The implementation of  "MkPoly".    "MkPoly" is a higher-order functor taking 3 arguments.     "N" - is a structure implementing natural numbers     "A" - is functor mapping "N" to an implementation of addition.     "M" - is a higher-order functor mapping "N" and "A" to an           implementation of multiplication *) functor  MkPoly =  functor(N:NAT) =>   functor(A:functor(X:NAT where type  nat = N.nat) ->                  sig val add:X.nat -> X.nat -> X.nat end) =>  functor(M:functor(X:NAT where type nat = N.nat)->	    functor(A:functor(Y:NAT where type nat = N.nat) ->		      sig  val add: Y.nat -> Y.nat-> Y.nat  end)->	    sig val mult: X.nat-> X.nat -> X.nat end) =>    struct       structure Nat = N;       structure Add = A  N;       structure Mult = M  N  A;       fun  eval x [] = Nat.z	 |  eval x (h::l) = Add.add h (Mult.mult x (eval x l))    end;  (* The implementations of  N, A, M. *) structure N =  struct type nat = int;         val z = 0;	 fun s i = i + 1;	 fun i b f 0 = b 	   | i b f n = f (i b f (n-1))   end; (* we implement addition by iterating successor *)functor A = functor(X:NAT where type nat = N.nat)=>               struct fun add n m = X.i n X.s m  	       end; (* we implement mulitiplication by iterating addition *)functor M = functor(X:NAT where type nat = N.nat)=>            functor(A:functor(Y:NAT where type nat = X.nat)->                                sig val add: Y.nat -> Y.nat -> Y.nat end)=>                    struct structure Add = A X;			   fun mult n m = X.i X.z (Add.add n) m                    end;  (* applying "MkPoly" ...  *)structure Poly = MkPoly N A M; (* evaluating  0(x^0) + 1(x^2)+ 0(x^3) + 1(x^4) at x = 2 yields 10 *)val test = Poly.eval 2 [0,1,0,1]; (* the functor "A'" is a more general version of "A". *)                                                              functor A' = functor(X:sig type nat;			   val s: nat->nat;			   val i: nat->(nat->nat)->nat->nat		       end)=>                      struct  val add =  fn n =>  fn m => X.i  n  X.s  m;                              fun sum b [] = b                                | sum b (h::l) = add h (sum b l)                      end;(* the application "MkPoly N A'" type checks even though the type of "A'"    is more general than required: *) structure Poly' = MkPoly N A' M; (* efficient implementations of  "N", "A" and "M"  that directly exploit integer addition and multiplication*) structure N = struct type  nat = int;		     val z =0;		     val s = fn i => i + 1;		     fun i b f 0 = b		       | i b f j = f (i b f (j-1))	      end; functor A = functor(X:sig  end)=>               struct val add = fn i => fn j => i + j               end; functor M = functor(X:sig  end)=>	    functor(A:functor(Y:NAT where type nat = int)->		      sig  end)=>	    struct val mult = fn i =>  fn j => i *  j	    end; (* a fast but not abstract implementation of "POLY" based on    the efficient versions of "N A M". *) structure IntPoly = MkPoly N A M;val test = IntPoly.eval 2 [0,1,0,1]; (* efficient and *abstract* implementations of  "N", "A" and "M" *)                  structure FastNat =  struct       structure N = N;       functor A = A;       functor M = M  end  :>  sig         structure N: NAT;         functor A:functor(X:sig end)->                             sig  val add:  N.nat->N.nat->N.nat  end;         functor M:functor(X:sig end)->		   functor(A:functor(Y:NAT where type nat = N.nat) ->			     sig end)->                   sig val mult: N.nat->N.nat->N.nat end  end; (* A fast and abstract implementation of POLY based   on the efficient and abstract implementation of FastNat. *) structure FastPoly = MkPoly FastNat.N FastNat.A FastNat.M;