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 }