1 module examples.safeDivision; 2 3 import either; 4 import std.traits; 5 import std.math; 6 7 version(unittest) { 8 import _expect; 9 } 10 11 bool isNaN(X)(X x) if (!isFloatingPoint!(X)) { 12 return false; 13 } 14 15 bool isNaN(X)(X x) if (isFloatingPoint!(X)) { 16 return std.math.isNaN(x); 17 } 18 19 /// 20 auto divideBy(NumericType)(NumericType numerator, NumericType denominator) { 21 enum NumericType zero = 0; 22 23 return denominator.bind 24 .when!(zero) ("Division by zero!".bindLeft) 25 .when!(isNaN!NumericType) ("Denominator is NaN.") 26 .when((NumericType a) => 27 numerator.bind 28 .when!(isNaN!NumericType) ("Numerator is NaN.".bindLeft) 29 .when((NumericType b) => b / a) 30 ); 31 } 32 33 /// divideBy with positive integers 34 unittest { 35 auto result = 10.divideBy(5); 36 37 result.isRight.should.equal(true); 38 39 result 40 .when((int value) { 41 value.should.equal(2); 42 }); 43 } 44 45 /// divideBy when the denominator is 0 46 unittest { 47 auto result = 10.divideBy(0); 48 49 result.isLeft.should.equal(true); 50 51 result 52 .when((string value) { 53 value.should.equal("Division by zero!"); 54 }); 55 } 56 57 /// divideBy when the denominator is NaN 58 unittest { 59 double nan; 60 61 auto result = double(10).divideBy(nan); 62 63 result.isLeft.should.equal(true); 64 65 result 66 .when((string value) { 67 value.should.equal("Denominator is NaN."); 68 }); 69 } 70 71 /// divideBy when the Numerator is NaN 72 unittest { 73 double nan; 74 75 auto result = double.nan.divideBy(3); 76 77 result.isLeft.should.equal(true); 78 79 result 80 .when((string value) { 81 value.should.equal("Numerator is NaN."); 82 }); 83 } 84 85 86 string toString(T)(Either!(string, T) result) { 87 import std.conv; 88 89 string message; 90 91 result 92 .when ((string error) { message = "Error: " ~ error; }) 93 .when ((T value) { message = value.to!string; }); 94 95 return "\t" ~ message ~ "\n"; 96 } 97 98 version(runExamples): 99 void main() { 100 import std.stdio; 101 102 writeln("30 / 4 = "); 103 30.divideBy(4) 104 .toString 105 .writeln; 106 107 writeln("12.2 / 23.2 = "); 108 double(12.2) 109 .divideBy(22.2) 110 .toString 111 .writeln; 112 113 writeln("12.2 / 0 = "); 114 double(12.2) 115 .divideBy(0) 116 .toString 117 .writeln; 118 119 writeln("12.2 / nan = "); 120 double(12.2) 121 .divideBy(double.nan) 122 .toString 123 .writeln; 124 125 writeln("nan / 3 = "); 126 double.nan 127 .divideBy(double(3)) 128 .toString 129 .writeln; 130 }