/* CSC 123/252 C# assignment sample solutions compile with mcs /checked csasnsol.cs /r:csasn1bases.dll /r:csasn2.dll /r:option.dll */ using System; // Part I (1) public class C : A, Ia, Ib { private B b = new B(); public override void g() { b.g(); } public virtual void h2() { b.h2(); } // the rest are directly inherited from A }//C // Part II (2) // Note, if you want to keep the items inherited from A protected // in the subclass, you can use direct inheritance on A, // but if they're to become public, you will need to adopt them // to public versions of the functions anyway. My solution // emulates both inheritances using "proxy" classes that // directly inherit from A and B and re-export the protected // methods as public. class proxyA2 : A2 { public void pf() { f(); } public void pg() { g(); } public void ph1() { h1(); } } class proxyB2 : B2 { public void pf() { f(); } public void pg() { g(); } public void ph2() { h2(); } } public class C2 { private proxyA2 a2 = new proxyA2(); private proxyB2 b2 = new proxyB2(); public void f() { a2.pf(); } public void g() { b2.pg(); } public void h1() { a2.ph1();} public void h2() { b2.ph2(); } } ///////////// PART II public static class part2 { // solutions to part 2 // I defined equals and times using match2_commute // 1. public static bool equals(number a, number b) => a.match2_commute(b, II:(i,k) => i.val==k.val, IF:(i,f) => i.val*f.d == f.n, IR:(i,r) => i.val*1.0 == r.val, IC:(i,c) => c.i==0 && i.val*1.0 == c.r, FF:(f,g) => f.n*g.d == f.d*g.n, FR:(f,r) => f.n*1.0 == r.val*f.d, FC:(f,c) => c.i==0 && f.n==c.r*f.d, RR:(r,s) => r.val == s.val, RC:(r,c) => c.i==0 && r.val == c.r, CC:(c,d) => c.r==d.r && c.i==d.i); // 2-times public static number times(number a, number b) { return a.match2_commute(b, II:(i,k) => new integer(i.val*k.val), IF:(i,f) => new rational(i.val*f.n,f.d), IR:(i,r) => new real(i.val*r.val), IC:(i,c) => new complex(c.r*i.val,i.val*c.i), FF:(f,g) => new rational(f.n*g.n, f.d*g.d), FR:(f,r) => new real(f.n*r.val / f.d), FC:(f,c) => new complex(c.r*f.n/f.d, c.i*f.n/f.d), RR:(r,s) => new real(r.val * s.val), RC:(r,c) => new complex(c.r*r.val, r.val*c.i), CC:(c,d) => new complex(c.r*d.r-c.i*d.i, c.i*d.r+c.r*d.i)); }//times // I "cheated" and used the simpler match2_upcast for add so there // are less cases to consider, but notice the call to .downcast() // at the end. Also note the call to add(f,c) to flip the arguments // using one-time recursion, because addition is also commutative. // 2-add public static number add(number a, number b) => a.match2_upcast(b, FF :(f,g) => new rational(f.n*g.d + f.d*g.n, f.d*g.d), CC :(c,d) => new complex(c.r+d.r, c.i+d.i), FC :(f,c) => new complex((f.n+c.r*f.d)/f.d, c.i), CF :(c,f) => add(f,c) ) .downcast(); // downcast here not required but nice to have, // otherwise may get a bunch of complex numbers. //3 public static number sum(number[] A) { number ax = new integer(0); foreach(number x in A) ax = add(ax,x); return ax; } //4 public static Option inverse(number n) => n.match( I: i => (i.val==0) ? Option.Nothing : Option.Make(new rational(1,i.val)), F: f => (f.n==0) ? Option.Nothing : Option.Make(new rational(f.d,f.n)), R: r => (r.val==0.0) ? Option.Nothing : Option.Make(new real(1.0/r.val)), C: c => { if (c.r==0.0 && c.i==0.0) return Option.Nothing; var s = c.r*c.r + c.i*c.i; return Option.Make(new complex(c.r/s,-1.0*c.i/s)); }); // in case you don't know, (A) ? B : C is a functional-style if-else, // equivalent to if (A) B else C. //5 public static Option divide(number a, number b) => inverse(b).map(invb => times(a,invb)); //6 // checked multiplication - assume compiled with /checked option public static Option safemult(Option a, Option b) => a.pair(b, (x,y) => { Option m; try { number n = times(x,y); m = Option.Make(n); } // try-checked : compile with /checked option catch (OverflowException oe) { Console.WriteLine("ERROR: "+oe.Message); m = Option.Nothing; } return m; } ).flatten(); // alternative solution to problem 6 using and_then (bind): public static Option safetimes(Option a, Option b) => a.and_then(x => b.and_then(y => { Option m; try { number n = times(x,y); m = Option.Make(n); } // try-checked : compile with /checked option catch (OverflowException oe) { Console.WriteLine("ERROR: "+oe.Message); m = Option.Nothing; } return m; })); public static number Randnum() { // generates a random number Random rnd = new Random(); int r = rnd.Next(0,4); switch (r) { case 0: return new integer(rnd.Next(-10,10)); case 1: return new rational(rnd.Next(-10,10),rnd.Next(1,10)); case 2: return new real(rnd.Next(0,200)/100.0); default: return new complex(rnd.Next(0,200)/100.0, rnd.Next(0,5)*1.0); }//switch } public static void main_wannabe() { number h1 = new rational(1,2); number r1 = new real(0.5); Console.WriteLine(equals(h1,r1)); number[] NUMS = new number[16]; for(int i=0;i<16;i++) NUMS[i] = Randnum(); foreach(var n in NUMS) Console.WriteLine(n); Console.WriteLine("sum : "+ sum(NUMS)); number pi = new real(3.1415927); number two = new integer(2); number f = new rational(0,1); divide(pi,two) // Some(pi/2) .map(x => times(x,new rational(2,3))) // Some(pi/3) .and_then(x => divide(x,f)) // None .match(some: v => {Console.WriteLine("the result is "+v);}, none: () => {Console.WriteLine("no result");}); //int nn = 0x7fffffff; //int.MaxValue; //checked { nn = nn+1; } var a = Option.Make(new integer(int.MaxValue)); var b = Option.Make(new integer(2)); Console.WriteLine("safemult(a,b): " + safemult(a,b)); safetimes(b,divide(pi,two)) // 2*pi/2 == pi .match( r => {Console.WriteLine("safetimes result: "+r);}, () => {Console.WriteLine("no safetimes result");}); }//main_wannabe }//part2 public class csasnsol { // main class public static void Main() { // part I-1 C n = new C(); n.f(); n.g(); n.h1(); n.h2(); // part I-2 C2 n2 = new C2(); n2.f(); n2.g(); n2.h1(); n2.h2(); // part II part2.main_wannabe(); }//main }