1 module dadt.example; 2 import std.stdio; 3 import dadt.parser; 4 5 enum code = ` 6 type Option(T) = 7 | Some of T 8 | None 9 [@@deriving show, ord, eq]; 10 `; 11 12 mixin(genCodeFromSource(code)); 13 14 auto bind(T, U)(Option!(T) arg, U function(T) proc) { 15 import std.traits; 16 17 static if (is(U == void)) { 18 alias R = void; 19 } else static if (__traits(isSame, TemplateOf!(U), Option) 20 || __traits(isSame, TemplateOf!(U), Some) || __traits(isSame, TemplateOf!(U), None)) { 21 alias R = U; 22 } else { 23 alias R = Option!U; 24 } 25 26 if ((cast(Some!T)arg) !is null) { 27 T val = (cast(Some!T)arg)._0; 28 29 static if (is(R == void)) { 30 proc(val); 31 return; 32 } 33 static if (is(R == U)) { 34 static if (__traits(isSame, TemplateOf!(U), Option) || __traits(isSame, 35 TemplateOf!(U), Some) || __traits(isSame, TemplateOf!(U), None)) { 36 return proc(val); 37 } 38 } else { 39 return some(proc(val)); 40 } 41 } else { 42 static if (is(R == void)) { 43 return; 44 } 45 static if (is(R == U)) { 46 return cast(Option!(TemplateArgsOf!U))none!(TemplateArgsOf!U); 47 } else { 48 static if (is(R == None!U)) { 49 return none!U; 50 } else { 51 throw new Error("<1>Error in bind! <incompatible type was given>"); 52 } 53 } 54 } 55 } 56 57 void testForOption() { 58 Option!int opt = some(100); 59 60 // dfmt off 61 opt.matchWithOption!(Option!int, int, 62 (Some!int _) => (int x) => x % 2 == 0 ? some(x) : none!(int), 63 (None!int _) => none!(int)) 64 .bind((int x) => some("x % 2 == 0!!")) 65 .matchWithOption!(void, string, 66 (Some!string _) => (string x) => writeln(x)); 67 68 Option!int ret = matchWithOption!(Option!int, int, 69 (Some!int _) => (int x) => some(x * x), 70 (None!int _) => none!(int))(opt); 71 72 ret.matchWithOption!(void, int, 73 (Some!int _) => (int x) => writeln("x is ", x), 74 (None!int _) => writeln("None!")); 75 76 opt.matchWithOption!(Option!int, int, 77 (Some!int _) => (int x) => x % 2 == 0 ? some(10) : none!int, 78 (None!int _) => _) 79 .matchWithOption!(void, int, 80 (Some!int _) => writeln("Some"), 81 (None!int _) => writeln("None")); 82 ret.show_Option.writeln; 83 //mixin(genCode(cast(TypeDeclare)DADT(code).buildAST)); 84 // dfmt on 85 Option!int a = some(1), b = some(2), c = some(3), d = none!int; 86 assert(compare_Option(a, a) == 0); 87 assert(compare_Option(a, b) == -1); 88 assert(compare_Option(c, b) == 1); 89 assert(compare_Option(a, d) == -1); 90 assert(compare_Option(d, d) == 0); 91 92 assert(equal_Option(a, a) == true); 93 assert(equal_Option(a, b) == false); 94 assert(equal_Option(d, d) == true); 95 } 96 97 enum code1 = ` 98 type Tree(T) = 99 | Node of Tree!(T) * Tree!(T) 100 | Leaf of T 101 `; 102 103 mixin(genCode(cast(TypeDeclare)DADT(code1).buildAST)); 104 105 string indent(size_t n) { 106 string ret; 107 foreach (i; 0 .. n) { 108 if (i % 2) { 109 ret ~= "| "; 110 } else { 111 ret ~= "|| "; 112 } 113 } 114 return ret; 115 } 116 117 string toString(T)(Tree!T tree, size_t depth = 0) { 118 import std.string; 119 120 string indent_str = indent(depth); 121 // dfmt off 122 return tree.matchWithTree!(string, T, 123 (Node!(int) _) => (Tree!int l, Tree!int r) => ` 124 %s|---<left>%s 125 %s| 126 %s|---<right>%s`.format(indent_str, toString!(T)(l, depth + 1), 127 indent_str, 128 indent_str, toString!(T)(r, depth + 1)), 129 (Leaf!(int) _) => (int v) => "%s".format(v)); 130 // dfmt on 131 } 132 133 void testForBinaryTree() { 134 Tree!int ti = node(node(leaf(1), leaf(2)), node(leaf(3), leaf(4))); 135 toString!int(ti).writeln; 136 } 137 138 enum codeEither = ` 139 type Either(T, U) = 140 | Right of T 141 | Left of U 142 `; 143 144 mixin(genCode(cast(TypeDeclare)DADT(codeEither).buildAST)); 145 146 Option!(T) isEitherRight(T, U)(Either!(T, U) arg) { 147 if ((cast(Right!(T, U))arg) !is null) { 148 T val = (cast(Right!(T, U))arg)._0; 149 return some(val); 150 } else { 151 return none!T; 152 } 153 } 154 155 auto then(T, U)(Option!(T) arg, U function(T) proc) { 156 static if (is(U == void)) { 157 alias R = void; 158 } else { 159 alias R = Option!U; 160 } 161 162 if ((cast(Some!T)arg) !is null) { 163 T val = (cast(Some!T)arg)._0; 164 proc(val); 165 } 166 } 167 168 void testForEither() { 169 Either!(int, string) funcEither(int x) { 170 if (x % 2 == 0) { 171 return right!(int, string)(x * x); 172 } else { 173 return left!(int, string)("error"); 174 } 175 } 176 177 Either!(int, string) e1 = funcEither(2), e2 = funcEither(3); 178 179 e1.isEitherRight!(int, string).then((int x) => writeln(x)); 180 } 181 182 void main() { 183 testForOption; 184 testForBinaryTree; 185 testForEither; 186 187 test; 188 } 189 190 void test() { 191 enum code = ` 192 type Option(T) = 193 | Some of T 194 | None 195 [@@deriving show, ord, eq]; 196 `; 197 writeln(code); 198 writeln("compile to ↓"); 199 TypeDeclare td = cast(TypeDeclare)DADT(code).buildAST; 200 (genCode(td)).writeln; 201 }