// What dynamic dispatch can't do naturally... open System open Option type number = | Integer of int | Rational of int*int | Real of float | Complex of float*float;; // reduce rationals like 3/6 to 1/2, a+0i to real a, etc let reduce n = match n with | Rational(n,d) -> let mutable a = n let mutable b = d while a<>0 && b<>0 do if a>b then a <- a%b else b <- b%a // <- is assignment (not =) let gcd = a+b let (n2,d2) = (n/gcd, d/gcd) if n2%d2=0 then Integer(n2/d2) else Rational(n2,d2) | Complex(r,0.0) -> Real(r) | _ -> n;; // all other numbers reduce to themselves // addition of any two numbers let rec add(x,y) = match (x,y) with | (Integer(a),Integer(b)) -> Integer(a+b) | (Integer(a), Rational(n,d)) -> reduce(Rational(a*d+n,d)) | (Integer(a), Real(b)) -> Real(float(a)+b) | (Integer(a), Complex(r,i)) -> reduce(Complex(float(a)+r,i)) | (Rational(a,b),Rational(c,d)) -> Rational(a*d+c*b,b*d) |> reduce | (Rational(a,b),Real(r)) -> Real(float(a)/float(b)+r) | (Rational(a,b),Complex(r,i))-> Complex(float(a)/float(b)+r,i) |> reduce | (Real(a),Real(b)) -> Real(a+b) | (Real(a),Complex(r,i)) -> Complex(a+r,i) |> reduce | (Complex(a,b),Complex(c,d)) -> Complex(a+c,b+d) |> reduce | (x,y) -> add(y,x);; // addition is commutative // multiplication of any two numbers let rec mult = function | (Integer(a),Integer(b)) -> Integer(a*b) | (Integer(a), Rational(n,d)) -> Rational(a*n,d) |> reduce | (Integer(a), Real(b)) -> Real(float(a)*b) | (Integer(a), Complex(r,i)) -> Complex(float(a)*r,i) |> reduce | (Rational(a,b),Rational(c,d)) ->Rational(a*c,b*d) |> reduce | (Rational(a,b),Real(r)) -> Real((float(a)*r)/float(b)) | (Rational(a,b),Complex(r,i))->Complex(float(a)*r/float(b),i) |> reduce | (Real(a),Real(b)) -> Real(a*b) | (Real(a),Complex(c,d)) -> Complex(a*c,a*d) |> reduce | (Complex(a,b),Complex(c,d)) -> Complex(a*c-b*d,b*c+a*d) |> reduce //(a+bi) * (c+di) = (ac-bd)i + (bc+ad)i | (x,y) -> mult(y,x);; // multiplication is commutative let rec inverse n : Option = match n with | Integer(n) when n<>0 -> Some(Rational(1,n)) | Rational(n,d) when n<>0 -> Some(reduce(Rational(d,n))) | Real(r) when r<>0.0 -> Some(Real(1.0/r)) | Complex(a,b) when a<>0.0 || b<>0.0 -> let s = a*a + b*b Some(Complex(a/s,-1.0*b/s)) | _ -> None;; // other numbers do not have inverse let divide(a,b) = (inverse b) |> Option.map (fun invb -> mult(a,invb)) // equality between any two numbers let rec numeq = function | (Integer(a),Integer(b)) -> a=b | (Integer(a), Rational(n,d)) -> a*d=n | (Integer(a), Real(b)) -> float(a)=b | (Integer(a), Complex(r,0.0)) -> float(a)=r | (Rational(a,b),Rational(c,d)) -> a*d = c*b | (Rational(a,b),Real(r)) ->float(a)/float(b) = r | (Rational(a,b),Complex(r,0.0))-> float(a)/float(b)=r | (Real(a),Real(b)) -> a=b | (Real(a),Complex(r,0.0)) -> a=r | (Complex(a,b),Complex(c,d)) -> a=c && b=d | (_,Complex(r,_)) -> false | (x,y) -> numeq(y,x);; // string form let tostring = function | Integer(n) -> string(n) | Rational(a,b) -> string(a)+"/"+string(b) | Real(a) -> string(a) | Complex(r,i) -> string(r)+"+"+string(i)+"i";; let somenums = [Real(3.14);Rational(3,4);Complex(0.1,2.0);Integer(2);Complex(2.0,0.0);Rational(1,2)];; let sum(Ns:number list) = // sum of all numbers in a number list let mutable i = 0 let mutable ax = Integer(0) // accumulator while i ax | (car::cdr) -> sum (add(ax,car)) cdr sum (Integer(0)) Ns;; let thesum = sum(somenums); Console.WriteLine( thesum ); printf "%s\n" (tostring(thesum));; // printf/printfn better than Console.. let n = Real(0.75); match divide(n,Integer(0)) with | Some(n) -> printfn "that's amazing" | None -> printfn "that's right" // search for a number in a list let result = List.exists (fun x -> numeq(x,n)) somenums; Console.WriteLine(string(result)); // or: for x in somenums do if numeq(x,n) then Console.WriteLine(tostring(x)+" is equal to "+tostring(n));;