// Numbers problem using pattern matching in F# (.Net version of OCAML) open System;; open Option;; type number = | Integer of int | Rational of int*int | Real of float | Complex of float*float;; let rec gcd = function // greatest common divisor with pattern matching | (0,a) -> a | (a,b) -> gcd(b%a,a);; // equality between any two numbers let rec numeq(x,y) = match (x,y) with | (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 | (x,y) -> numeq(y,x);; // addition of any two numbers (recall no dyn. dispatch on two objects at once) let rec add = function // same as (x,y) -> match (x,y) with ... | (Integer(a),Integer(b)) -> Integer(a+b) | (Integer(a), Rational(n,d)) -> Rational(a*d+n,d) | (Integer(a), Real(b)) -> Real(float(a)+b) | (Integer(a), Complex(r,i)) -> Complex(float(a)+r,i) | (Rational(a,b),Rational(c,d)) ->Rational(a*d+c*b,b*d) | (Rational(a,b),Real(r)) -> Real(float(a)/float(b)+r) | (Rational(a,b),Complex(r,i))->Complex(float(a)/float(b)+r,i) | (Real(a),Real(b)) -> Real(a+b) | (Real(a),Complex(r,i)) -> Complex(a+r,i) | (Complex(a,b),Complex(c,d)) -> Complex(a+c,b+d) | (x,y) -> add(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";; // multiplication (curried) let rec times x y = match (x,y) with | (Integer(a),Integer(b)) -> Integer(a*b) | (Integer(a),Rational(n,d)) -> Rational(a*n,d) | (Integer(a),Real(b)) -> Real(float(a)*b) | (Integer(a),Complex(r,i)) -> Complex(float(a)*r,float(a)*i) | (Rational(a,b),Rational(c,d)) -> Rational(a*c,b*d) | (Rational(a,b),Real(r)) -> Real(float(a)*r/float(b)) | (Rational(a,b),Complex(r,i)) -> let rr = float(a)*r/float(b) let ii = float(a)*i/float(b) Complex(rr,ii) | (Real(a),Real(b)) -> Real(a*b) | (Real(a),Complex(r,i)) -> Complex(a*r,i*r) | (Complex(a,b),Complex(c,d)) -> Complex(a*c-b*d,a*d+b*c) | _ -> times y x;; // times is commutative ///// Monadic error handling // find multiplicative inverse of a number, if it exists: let inverse = function | Integer(n) when n<>0 -> Some (Rational(1,n)) | Rational(n,d) when n<>0 -> Some(Rational(d,n)) | Real(r) when r<>0.0 -> Some(Real(1.0/r)) | Complex(r,i) when not(r=0.0 && i=0.0) -> let d = r*r + i*i in Some(Complex(r/d, i/d)) | _ -> None // define division by muliplying with inverse: let divide a b = (inverse b) |> map (fun i -> times a i);; let div1 = divide (Integer 3) (Rational(0,1));; let div2 = divide (Integer 3) (Rational(1,2));; // Monadic error handling allows us to proceed with computation // as if no error has occurred, because the error has been wrapped // inside a "monad". div1 |> map tostring |> map Console.WriteLine |> ignore;; // Additional "monadic combinators": let if_else forsome fornone = function | None -> fornone() | Some x -> forsome x;; // type of if_else is ('a -> 'b) -> (unit -> 'b) -> 'a option -> 'b let map_or forsome fornone = function | None -> fornone(); None | Some x -> Some(forsome x);; // type of map_or is ('a -> 'b) -> (unit -> unit) -> 'a option -> 'b option div2 |> map (fun x -> add (x,Integer(100))) |> bind (fun x -> divide x (Integer 2)) |> map tostring |> if_else Console.WriteLine (fun () -> Console.WriteLine("no value")) printfn "-------" 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) = let mutable i = 0 let mutable ax = Integer(0) // accumulator while i