-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
110 lines (88 loc) · 3.2 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!./node_modules/.bin/ts-node
import { u, U, cr } from "./unit";
//import { getStrM, putStrM, pure, guess } from "./IOMonad";
import { getStrM, putStr, putStrM, pure, IO } from "./maybeIOPromise";
import { Maybe } from "./maybe";
import { log } from "./logging";
//https://www.youtube.com/watch?v=vkcxgagQ4bM 21:15 ... you might be asking, what is this U?
// The next line is a problem, because it uses the heap. The compiler needs to do a lot more work
// to build monadic code efficiently, largely eliminating this new, according to the context.
// Since we are explicitly calling new, this will be tricky.
// The compiler will take this new instruction literally. This is the main point of Bartosz's
// lecture, its a howto and a warning: take this code seriously, it presents problems for compilers.
// C++ has big issues with it, and typescript suffers too.
// There are workarounds, based on coroutines, which can allocate memory more efficiently.
const prompt =
<V>(str: string) =>
(x: V) =>
putStrM(str);
export const test = IO.root(u)
.fbind(prompt("hello"))
.fbind(prompt(" world!\n"));
//test2.run();
const low = 1;
const high = 1024;
export const test2 = test
.fbind(prompt("What is your name?\n"))
.fbind(getStrM)
.then((s) => s.toUpperCase())
.fbind((name) => putStrM(cr + "Hi " + name + cr));
// Works out the box in typescript! That's an improvement over C++ that has problems
// when the thunk is strongly typed, requiring the std::function hack described by Bartosz.
export const ask = (i: number) => {
return putStrM("Is it less than: ")
.fbind((x) => putStrM(i.toString()))
.fbind((x) => putStrM("? (y/n)" + cr))
.fbind(getStrM)
.fbind((s) => pure(s === "y"));
};
export const guess = (a: number, b: number): IO<number> => {
if (a >= b) return pure(a);
const m = (b + 1 + a) / 2;
return ask(m).fbind((yes: boolean) => {
return yes ? guess(a, m - 1) : guess(m, b);
});
};
const test3 = test2
.fbind(
prompt(
"Think of a number between " +
low.toString() +
" and " +
high.toString() +
cr
)
)
.fbind((x) => guess(low, high))
.fbind((ans) => putStrM(cr + "The answer is: " + ans.toString()));
export function delay(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Maybe.just(10)
.fmap((x) => x + 1)
.fmap((x) => x.toString())
.fmap((s) => {
console.log(s);
return s;
})
.finally("default");
//Promises fire off their resolution as soon as they are created.
//For IO composition, we need to defer this.
test3
.exec("A non-result")
.then((res) => log().info("Answer from monad: ").info(res));
//A controlled usage of any increases typescripts deductive powers. Why? addProp should just work without this kind of hackery.
declare type EnvironmentData = any;
const addPropValueAux =
<O, N>(oldData: O) =>
(newData: N): O & N =>
Object.assign({}, oldData, newData);
const addPropValue = (oldData: EnvironmentData) => (newData: EnvironmentData) =>
addPropValueAux<typeof oldData, typeof newData>(oldData)(newData);
const exist2 = {
userName: "John Smith",
};
const ext = addPropValue(exist2)({
email: "jsmith@anotherplace.com",
});
console.log(ext.userName + " " + ext.email);