aboutsummaryrefslogtreecommitdiff
path: root/samples
diff options
context:
space:
mode:
authorMarvin Borner2024-11-27 02:12:12 +0100
committerMarvin Borner2024-11-27 02:27:48 +0100
commit6da602b0a29afcd2aa15725547375a80e30b3983 (patch)
treebb268dc7935696c2687c4ec151c2e0108536fa6f /samples
initial commit
Diffstat (limited to 'samples')
-rw-r--r--samples/either.js19
-rw-r--r--samples/io.js42
-rw-r--r--samples/maybe.js18
-rw-r--r--samples/parser.js13
-rw-r--r--samples/state_lambda.js37
-rw-r--r--samples/state_rng.js14
-rw-r--r--samples/state_writer.js13
7 files changed, 156 insertions, 0 deletions
diff --git a/samples/either.js b/samples/either.js
new file mode 100644
index 0000000..e9ad679
--- /dev/null
+++ b/samples/either.js
@@ -0,0 +1,19 @@
+import * as either from "../src/either.js"
+import * as fs from "fs"
+
+function divide(a, b) {
+ if (b === 0)
+ return either.Left("Error: Division by zero!")
+ return either.Right(a / b)
+}
+
+// try piping 42 or 0 into stdin
+const input = +fs.readFileSync(0, "utf-8");
+const result = either.DO(function* () {
+ const a = yield divide(42, input)
+ const b = yield divide(42, a)
+ const c = yield divide(b, a)
+ return c
+})
+
+console.log(either.show(result));
diff --git a/samples/io.js b/samples/io.js
new file mode 100644
index 0000000..a2a0ff0
--- /dev/null
+++ b/samples/io.js
@@ -0,0 +1,42 @@
+import * as io from "../src/io.js"
+import * as fs from "fs"
+
+const writeLine = str => io.DO(function* () {
+ const head = str[0]
+ const tail = str.slice(1)
+
+ yield io.write(head)
+ yield tail === "" ? io.write('\n') : writeLine(tail)
+})
+
+const readLine = io.bind(io.read)(ch =>
+ ch === '\r' ? io.unit("")
+ : io.bind(readLine)(line => io.unit(ch + line))
+)
+
+const nodeEffects = () => {
+ process.stdin.setRawMode(true)
+ const buffer = Buffer.alloc(1)
+ const fd = fs.openSync("/dev/tty", "rs")
+ return {
+ write: process.stdout.write.bind(process.stdout),
+ read: () => {
+ fs.readSync(fd, buffer, 0, 1)
+ return buffer.toString("utf8")
+ }
+ }
+}
+
+const Person = name => age => person => person(name)(age)
+
+const constructPerson = io.DO(function* () {
+ yield writeLine("Please enter your name!")
+ const name = yield readLine
+ yield writeLine(`Hello ${name}! Now please enter your age.`)
+ const age = yield readLine
+ return Person(name)(age) // arbitrary data!
+})
+
+console.log(constructPerson(nodeEffects())(st => v => v(
+ name => age => `Person(name: ${name}, age: ${age})`
+)));
diff --git a/samples/maybe.js b/samples/maybe.js
new file mode 100644
index 0000000..0276f94
--- /dev/null
+++ b/samples/maybe.js
@@ -0,0 +1,18 @@
+import * as maybe from "../src/maybe.js"
+import * as fs from "fs"
+
+function divide(a, b) {
+ if (b === 0)
+ return maybe.Nothing
+ return maybe.Just(a / b)
+}
+
+const input = +fs.readFileSync(0, "utf-8");
+const result = maybe.DO(function* () {
+ const a = yield divide(42, input)
+ const b = yield divide(42, a)
+ const c = yield divide(b, a)
+ return c
+})
+
+console.log(maybe.show(result))
diff --git a/samples/parser.js b/samples/parser.js
new file mode 100644
index 0000000..80d4aaa
--- /dev/null
+++ b/samples/parser.js
@@ -0,0 +1,13 @@
+import * as parser from "../src/parser.js"
+import * as fs from "fs"
+
+// try piping "Hello, World" into stdin!
+const input = fs.readFileSync(0, "utf-8");
+
+const parse = parser.DO(function* () {
+ const p = yield parser.string("Hello")
+ yield parser.char(',')
+ yield parser.char(' ')
+ return p
+})
+console.log(parser.show(parse(input)))
diff --git a/samples/state_lambda.js b/samples/state_lambda.js
new file mode 100644
index 0000000..8cebcec
--- /dev/null
+++ b/samples/state_lambda.js
@@ -0,0 +1,37 @@
+// translating de Bruijn levels in lambda terms to unique variables
+import * as state from '../src/state.js'
+
+const Abs = n => m => abs => app => lvl => abs(n)(m)
+const App = f => x => abs => app => lvl => app(f)(x)
+const Lvl = l => abs => app => lvl => lvl(l)
+
+const transform = term => term
+ // case: Abstraction
+ (_ => m => state.DO(function* () {
+ const {ctr, stk} = yield state.get
+ yield state.put({ctr: ctr + 1, stk: [ctr, ...stk]})
+ const _m = yield transform(m)
+ yield state.modify(({ctr}) => ({ctr, stk}))
+ return Abs(ctr)(_m)
+ }))
+ // case: Application
+ (f => x => state.ap
+ (state.fmap(App)(transform(f)))
+ (transform(x))
+ )
+ // case: de Bruijn level
+ (l => state.DO(function* () {
+ const {stk} = yield state.get
+ return Lvl(stk[stk.length - l - 1])
+ }))
+
+const prettyTerm = term => term
+ (n => m => `λ${n}.${prettyTerm(m)}`)
+ (f => x => `(${prettyTerm(f)} ${prettyTerm(x)})`)
+ (l => l)
+
+// (λλ(0 0) λ0)
+const term = App(Abs()(Abs()(App(Lvl(0))(Lvl(0)))))(Abs()(Lvl(0)))
+
+console.log(transform(term)({ctr: 0, stk: []})(_ => t => prettyTerm(t)))
+// (λ0.λ1.(0 0) λ2.2)
diff --git a/samples/state_rng.js b/samples/state_rng.js
new file mode 100644
index 0000000..efb8ff3
--- /dev/null
+++ b/samples/state_rng.js
@@ -0,0 +1,14 @@
+import * as state from '../src/state.js'
+
+const rng = max => seed => (1103515245 * seed + 12345) % max
+const rand = seed => (g => state.State(g)(g))(rng(1000)(seed))
+
+// or, simply:
+const threeNumbers = state.DO(function* () {
+ const a = yield rand
+ const b = yield rand
+ const c = yield rand
+ return [a, b, c]
+})
+
+console.log(threeNumbers(161)(st => v => v)) // [790, 895, 620]
diff --git a/samples/state_writer.js b/samples/state_writer.js
new file mode 100644
index 0000000..081e9f1
--- /dev/null
+++ b/samples/state_writer.js
@@ -0,0 +1,13 @@
+import * as state from '../src/state.js'
+
+const log = (a, str) => st => state.State(a)(st + str)
+
+const deepthought = state.DO(function* () {
+ const answer = yield log(42, "Finding answer... ")
+ const correct = yield log(answer == 42, "Checking answer... ")
+ if (correct) yield log(null, "Is correct!")
+ else yield log(null, "Is false!")
+ return answer
+})
+
+console.log(deepthought("")(log => answer => ({answer, log})))