diff options
author | Marvin Borner | 2024-11-27 02:12:12 +0100 |
---|---|---|
committer | Marvin Borner | 2024-11-27 02:27:48 +0100 |
commit | 6da602b0a29afcd2aa15725547375a80e30b3983 (patch) | |
tree | bb268dc7935696c2687c4ec151c2e0108536fa6f /samples |
initial commit
Diffstat (limited to 'samples')
-rw-r--r-- | samples/either.js | 19 | ||||
-rw-r--r-- | samples/io.js | 42 | ||||
-rw-r--r-- | samples/maybe.js | 18 | ||||
-rw-r--r-- | samples/parser.js | 13 | ||||
-rw-r--r-- | samples/state_lambda.js | 37 | ||||
-rw-r--r-- | samples/state_rng.js | 14 | ||||
-rw-r--r-- | samples/state_writer.js | 13 |
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}))) |