// What language is this??? It's Java 21! import java.util.Optional; // interface number defined below record Int(int x) implements number {} record Rat(int n, int d) implements number { public Rat { assert d != 0 : "zero denominator in rational number"; } //assertions trigger error if run with java -ea } record Real(double r) implements number {} record Complex(double r, double i) implements number {} record pair(number a, number b) {} interface number { default boolean equals(number other) { var a_and_b = new pair(this,other); return switch (a_and_b) { case pair(Int(int x), Int(int y)) -> x==y; case pair(Int(int x), Rat(int n, int d)) -> x*d==n; case pair(Int(int x), Real(double r)) -> 1.0*x == r; case pair(Int(int x), Complex(double r, double i)) when i==0.0 -> 1.0*x == r; case pair(Rat(int a, int b), Rat(int c, int d)) -> a*d == b*c; case pair(Rat(int a, int b), Real(double r)) -> a*1.0 == b*r; case pair(Rat(int a,int b), Complex(double r,double i)) when i==0.0 -> a*1.0 == b*r; case pair(Real(double a),Real(double b)) -> a==b; case pair(Real(double a),Complex(double r,double i)) when i==0.0 -> a==r; case pair(Complex(double a, double b),Complex(double c,double d)) -> a==c && b==d; case pair(number a, number b) -> b.equals(a); // default -> false; // not needed in this case };//switch (match) }//equal default number multiply(number other) { var a_and_b = new pair(this,other); return switch (a_and_b) { case pair(Int(int x), Int(int y)) -> new Int(x*y); case pair(Int(int x), Rat(int n, int d)) -> new Rat(x*n,d); case pair(Int(int x), Real(double r)) -> new Real(x*r); case pair(Int(int x), Complex(double r, double i)) -> new Complex(x*r,x*i); case pair(Rat(int a, int b), Rat(int c, int d)) -> new Rat(a*c,b*d); case pair(Rat(int a, int b), Real(double r)) -> new Real(a*r/b); case pair(Rat(int a,int b), Complex(double r,double i)) -> new Complex(a*r/b,a*i/b); case pair(Real(double a),Real(double b)) -> new Real(a*b); case pair(Real(double a),Complex(double r,double i)) -> new Complex(a*r,a*i); case pair(Complex(double a, double b),Complex(double c,double d)) -> new Complex(a*c-b*d,a*d+b*c); case pair(number a, number b) -> b.multiply(a); };//switch }//multiply default Optional inverse() { // multiplicative inverse switch (this) { case Int(int x) when x!=0: return Optional.of(new Rat(1,x)); case Rat(int n, int d) when n!=0: return Optional.of(new Rat(d,n)); case Real(double r) when r!=0.0: return Optional.of(new Real(1.0/r)); case Complex(double r, double i) when r!=0.0 || i!=0.0: var d = r*r + i*i; return Optional.of(new Complex(r/d,i/d)); default: return Optional.empty(); }//switch }//inverse // implment division by multiplying with inverse, // with monadic error handling default Optional divide(number other) { return other.inverse().map(inv -> this.multiply(inv)); }//divide static int gcd(int a, int b) { while (a!=0 && b!=0) { if (a>b) a = a%b; else b = b%a; } return a+b; }//gcd default String tostr() { // can't override toString in interface switch (this) { case Int(int x): return x+""; case Rat(int n,int d) when n%d==0: return ""+(n/d); case Rat(int n,int d): var c = gcd(n,d); return (n/c) + "/" + (d/c); case Real(double r): return ""+((int)(r*1000+0.5)/1000.0); case Complex(double r,double i) when i==0.0: return new Real(r).tostr(); case Complex(double r,double i): var rr = (int)(r*1000+0.5)/1000.0; var ir = (int)(i*1000+0.5)/1000.0; return rr+ "+" + ir + "i"; default : return ""; }//switch }//tostr }//number interface public class numbers { public static void main(String[] args) { number N[] = { new Int(4), new Real(4.3), new Rat(2,7), new Complex(2.0,1.0), new Rat(1,3), new Real(0.2) }; number product = new Int(1); for(var n:N) product = product.multiply(n); System.out.printf("product: %s\n", product.tostr()); product.divide(new Real(2.0)) .ifPresent(x -> System.out.printf("product/2: %s\n",x.tostr())); System.out.println("div by zero? " + product.divide(new Rat(0,1))); }//main }