diff --git a/new/index.html b/new/index.html deleted file mode 100644 index 8f27113..0000000 --- a/new/index.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - -

-
-

Documentation

-

use (name; value) to define something. the definition can be recursive. value is executed and name is set to the final state of the stack, i.e. (name; 1 3) is possible

-

use ' to push instead of apply to the stack, e.g. '(a -> a). This is useful for lazyness, i.e. '(->lazy evaluated thing)

- - \ No newline at end of file diff --git a/new/main.js b/new/main.js deleted file mode 100644 index e75a75e..0000000 --- a/new/main.js +++ /dev/null @@ -1,52 +0,0 @@ -import {execRPN} from './shiny.mjs'; -import {parseExprs} from './parse.mjs'; -import {tokenize} from './token.mjs'; -import {scope, customHandler} from './builtin.mjs'; - -const inbox = document.getElementById("inbox") -const outbox = document.getElementById("outbox") -const submit = document.getElementById("submit") - -const show = (elem) => { - if (elem.type === "pair") { - return "{" + show(elem.val.fst) + ", " + show(elem.val.snd) + "}" - } else if (elem.type === "closure") { - return "(needs: " + elem.val.args.join(", ") + ")" - } else if (elem.type === "array") { - return "[" + prettyprint(elem.val) + "]" - } else { - return "(" + elem.val + ": " + elem.type + ")" - } -} - -const prettyprint = (out) => { - let str = ""; - for (let i = 0; i < out.length; i++) { - str += show(out[i]); - if (i < out.length - 1) { - str += " "; - } - } - return str; -} - -submit.onclick = (event) => { - const input = inbox.value; - let toks = tokenize(input); - if (!toks) { - outbox.innerHTML = "could not parse input: " + input; - return; - } - let ast = parseExprs(toks); - if (ast.stream.length !== 0) { - outbox.innerHTML = "unexpected token: " + ((e)=>{if(e.type==="ident"){return e.name}else{return e.val}})(ast.stream[0]); - return; - } - let out = execRPN(scope, ast.parsed, customHandler); - if (!out) { - outbox.innerHTML = "failed to execute"; - return; - } - console.log(out); - outbox.innerHTML = prettyprint(out.stacks[0]); -} \ No newline at end of file diff --git a/new/token.mjs b/new/token.mjs deleted file mode 100644 index 6276cd9..0000000 --- a/new/token.mjs +++ /dev/null @@ -1,40 +0,0 @@ -export function tokenize(input) { - let i; - let inputWithAddedSpaces = ""; - const syntax = /['";()]/; - for(i = 0; i"){ - if(input.charAt(i-1) != " "){ - inputWithAddedSpaces += " "; - } - if(input.charAt(i+2) != " "){ - inputWithAddedSpaces += "->" + " "; - } else { - inputWithAddedSpaces += "->"; - } - } else if(input.charAt(i) != ">") { - inputWithAddedSpaces += input.charAt(i); - } - } - let splitInput = inputWithAddedSpaces.split(" ").filter((s) => s !== ""); - let output = []; - for(i = 0; i"){ - output.push({type: "syntax", val:splitInput[i]}); - } else if(splitInput[i] != '') { - output.push({type: "ident", name:splitInput[i]}); - } - } - return(output) -} \ No newline at end of file diff --git a/npm-debug.log b/npm-debug.log deleted file mode 100644 index 2f67d2c..0000000 --- a/npm-debug.log +++ /dev/null @@ -1,96 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'i', 'rationals' ] -2 info using npm@3.5.2 -3 info using node@v8.10.0 -4 verbose config Skipping project config: /home/aidan/.npmrc. (matches userconfig) -5 silly loadCurrentTree Starting -6 silly install loadCurrentTree -7 silly install readLocalPackageData -8 silly fetchPackageMetaData rationals -9 silly fetchNamedPackageData rationals -10 silly mapToRegistry name rationals -11 silly mapToRegistry using default registry -12 silly mapToRegistry registry https://registry.npmjs.org/ -13 silly mapToRegistry uri https://registry.npmjs.org/rationals -14 verbose request uri https://registry.npmjs.org/rationals -15 verbose request no auth needed -16 info attempt registry request try #1 at 19:23:48 -17 verbose request id 1f9e752341fc452f -18 verbose etag W/"e0fb616d3d75eb1a38936789fa99e693" -19 verbose lastModified Sat, 12 Oct 2019 22:31:44 GMT -20 http request GET https://registry.npmjs.org/rationals -21 http 304 https://registry.npmjs.org/rationals -22 verbose headers { date: 'Mon, 01 Jun 2020 18:23:48 GMT', -22 verbose headers connection: 'keep-alive', -22 verbose headers 'set-cookie': -22 verbose headers [ '__cfduid=da1ea1de35cfdbd41bc4da4edd15edf091591035828; expires=Wed, 01-Jul-20 18:23:48 GMT; path=/; domain=.npmjs.org; HttpOnly; SameSite=Lax' ], -22 verbose headers 'cf-ray': '59caf7cabb5ad210-MAN', -22 verbose headers age: '10', -22 verbose headers 'cache-control': 'public, max-age=300', -22 verbose headers etag: '"e0fb616d3d75eb1a38936789fa99e693"', -22 verbose headers 'last-modified': 'Sat, 12 Oct 2019 22:31:44 GMT', -22 verbose headers vary: 'Accept-Encoding', -22 verbose headers 'cf-cache-status': 'HIT', -22 verbose headers 'cf-request-id': '0312b932ae0000d2108792b200000001', -22 verbose headers 'expect-ct': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"', -22 verbose headers server: 'cloudflare' } -23 silly get cb [ 304, -23 silly get { date: 'Mon, 01 Jun 2020 18:23:48 GMT', -23 silly get connection: 'keep-alive', -23 silly get 'set-cookie': -23 silly get [ '__cfduid=da1ea1de35cfdbd41bc4da4edd15edf091591035828; expires=Wed, 01-Jul-20 18:23:48 GMT; path=/; domain=.npmjs.org; HttpOnly; SameSite=Lax' ], -23 silly get 'cf-ray': '59caf7cabb5ad210-MAN', -23 silly get age: '10', -23 silly get 'cache-control': 'public, max-age=300', -23 silly get etag: '"e0fb616d3d75eb1a38936789fa99e693"', -23 silly get 'last-modified': 'Sat, 12 Oct 2019 22:31:44 GMT', -23 silly get vary: 'Accept-Encoding', -23 silly get 'cf-cache-status': 'HIT', -23 silly get 'cf-request-id': '0312b932ae0000d2108792b200000001', -23 silly get 'expect-ct': 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"', -23 silly get server: 'cloudflare' } ] -24 verbose etag https://registry.npmjs.org/rationals from cache -25 verbose get saving rationals to /home/aidan/.npm/registry.npmjs.org/rationals/.cache.json -26 silly install normalizeTree -27 silly loadCurrentTree Finishing -28 silly loadIdealTree Starting -29 silly install loadIdealTree -30 silly cloneCurrentTree Starting -31 silly install cloneCurrentTreeToIdealTree -32 silly cloneCurrentTree Finishing -33 silly loadShrinkwrap Starting -34 silly install loadShrinkwrap -35 silly loadShrinkwrap Finishing -36 silly loadAllDepsIntoIdealTree Starting -37 silly install loadAllDepsIntoIdealTree -38 verbose stack Error: Missing required argument #1 -38 verbose stack at andLogAndFinish (/usr/share/npm/lib/fetch-package-metadata.js:31:3) -38 verbose stack at fetchPackageMetadata (/usr/share/npm/lib/fetch-package-metadata.js:51:22) -38 verbose stack at resolveWithNewModule (/usr/share/npm/lib/install/deps.js:456:12) -38 verbose stack at /usr/share/npm/lib/install/deps.js:190:5 -38 verbose stack at /usr/share/npm/node_modules/slide/lib/async-map.js:52:35 -38 verbose stack at Array.forEach () -38 verbose stack at /usr/share/npm/node_modules/slide/lib/async-map.js:52:11 -38 verbose stack at Array.forEach () -38 verbose stack at asyncMap (/usr/share/npm/node_modules/slide/lib/async-map.js:51:8) -38 verbose stack at exports.loadRequestedDeps (/usr/share/npm/lib/install/deps.js:188:3) -39 verbose cwd /home/aidan/Desktop/js-projects/rpncalc-v4 -40 error Linux 5.3.0-53-generic -41 error argv "/usr/bin/node" "/usr/bin/npm" "i" "rationals" -42 error node v8.10.0 -43 error npm v3.5.2 -44 error code EMISSINGARG -45 error typeerror Error: Missing required argument #1 -45 error typeerror at andLogAndFinish (/usr/share/npm/lib/fetch-package-metadata.js:31:3) -45 error typeerror at fetchPackageMetadata (/usr/share/npm/lib/fetch-package-metadata.js:51:22) -45 error typeerror at resolveWithNewModule (/usr/share/npm/lib/install/deps.js:456:12) -45 error typeerror at /usr/share/npm/lib/install/deps.js:190:5 -45 error typeerror at /usr/share/npm/node_modules/slide/lib/async-map.js:52:35 -45 error typeerror at Array.forEach () -45 error typeerror at /usr/share/npm/node_modules/slide/lib/async-map.js:52:11 -45 error typeerror at Array.forEach () -45 error typeerror at asyncMap (/usr/share/npm/node_modules/slide/lib/async-map.js:51:8) -45 error typeerror at exports.loadRequestedDeps (/usr/share/npm/lib/install/deps.js:188:3) -46 error typeerror This is an error with npm itself. Please report this error at: -46 error typeerror -47 verbose exit [ 1, true ] diff --git a/new/builtin.mjs b/script/builtin.mjs similarity index 62% rename from new/builtin.mjs rename to script/builtin.mjs index 4999dcf..df3ac7a 100644 --- a/new/builtin.mjs +++ b/script/builtin.mjs @@ -1,6 +1,4 @@ -import {defnOp, makeOp, defn} from './shiny.mjs'; -import {parseExprs} from './parse.mjs'; -import {tokenize} from './token.mjs'; +import {defnOp, makeOp} from './shiny.mjs'; const objEq = (a, b) => { if (typeof a !== 'object' && typeof b !== 'object') { @@ -27,29 +25,13 @@ const objEq = (a, b) => { export let scope = {}; -export const customHandler = (ins) => { - return [ins]; -} - -const addRPNDefn = (name, def) => { - let toks = tokenize(def); - if (!toks) { - throw 'could not load builtin' - } - let ast = parseExprs(toks); - if (!ast.parsed) { - throw 'could not load builtin' - } - scope = defn(name, ast.parsed, scope); -} - -const assertType = (type) => (elem) => { +export const assertType = (type) => (elem) => { if (elem.type !== type) { throw 'typeerror' } } -const addDefn = (name, args, fn) => { +export const addDefn = (name, args, fn) => { if (Array.isArray(args)) { const nargs = [...Array(args.length).keys()]; const liftFn = (scope) => { @@ -83,12 +65,25 @@ const mult = (args) => [{type:"num", val:args[0] * args[1]}]; const pow = (args) => [{type:"num", val:Math.pow(args[0], args[1])}]; const root = (args) => [{type:"num", val:Math.sqrt(args[0])}]; const type = (args) => [{type:"type", val:args[0].type}]; -const pair = (args) => [{type:"pair", val:{fst:args[0], snd:args[1]}}]; -const fst = (args) => [args[0].fst]; -const snd = (args) => [args[0].snd]; -const tuple = (args) => makeOp([...Array(args[0]).keys()], (args) => {return [{type:"tuple", val:args}]}); -const index = (args) => args[0][args[1]]; +const index = (args) => [args[0][args[1]]]; const len = (args) => [{type:"num", val:args[0].length}]; +const untuple = (args) => args[0]; + +const coerce = (args) => { + if (args[1].type === "type") { + return [{type:args[1].val, val:args[0].val}]; + } else { + throw 'typeerror' + } +} + +const tuple = (args) => makeOp([...Array(args[0]).keys()], (iargs) => { + let arr = []; + for (let i = 0; i < args[0]; i++) { + arr.push(iargs[i][0]); + } + return [{type:"tuple", val:arr}] +}); const eq = (args) => { console.log(args[2], args[3]) @@ -106,19 +101,9 @@ addDefn("*", ["num", "num"], mult); addDefn("^", ["num", "num"], pow); addDefn("sqrt", ["num"], root); addDefn("==", 4, eq); -addDefn("pair", 2, pair); -addDefn("fst", ["pair"], fst); -addDefn("snd", ["pair"], snd); addDefn("tuple", ["num"], tuple); addDefn("!!", ["tuple", "num"], index); addDefn("len", ["tuple"], len); +addDefn("untuple", ["tuple"], untuple); addDefn("typeof", 1, type); -addRPNDefn("stop", "\"stop"); -addRPNDefn("inv", "(x -> 1 x /)"); -addRPNDefn("fold", "(x acc fn -> acc '(-> x acc fn 'fn fold) 'x stop ==)"); -addRPNDefn("range", "(x y -> x '(->x x 1 + y range) 'x y ==)"); -addRPNDefn("listthen", "(fn -> (internal; x acc -> '(->acc fn) '(->x acc pair internal) x stop ==) 0 tuple internal)"); -addRPNDefn("list", "'(a -> a) listthen"); -addRPNDefn("lmap", "(list fn -> list '(->list fst fn list snd 'fn lmap pair) list 0 tuple ==)"); -addRPNDefn("unlist", "(l -> (internal; list -> '(->) '(->list fst list snd internal) list 0 tuple ==) stop l internal)"); -addRPNDefn("map", "fn -> '(l->l 'fn lmap unlist) listthen"); \ No newline at end of file +addDefn("coerce", 2, coerce); \ No newline at end of file diff --git a/script/dom.mjs b/script/dom.mjs new file mode 100644 index 0000000..33312dc --- /dev/null +++ b/script/dom.mjs @@ -0,0 +1,33 @@ +import {assertType, addDefn} from './builtin.mjs'; +import {execFn} from './shiny.mjs'; + +const getElem = (args) => [{type:"domNode", val:document.getElementById(args[0])}]; +const setHTML = (args) => args[0].innerHTML = args[1]; +const mutref = (args) => [{type:"&mut", val:args[0]}]; +const readmut = (args) => [args[0]]; + +const log = (args) => { + console.log(args); + return []; +} + +const writemut = (args) => { + assertType("&mut", args[1]); + args[1].val = args[0]; + return []; +} + +const onclick = (args) => { + args[0].onclick = (_) => { + execFn(args[1]); + } + return []; +} + +addDefn("log", 1, log); +addDefn("getId", ["string"], getElem); +addDefn("setHTML", ["domNode", "string"], setHTML); +addDefn("mutref", 1, mutref); +addDefn("readmut", ["&mut"], readmut); +addDefn("writemut", 2, writemut); +addDefn("onclick", ["domNode", "closure"], onclick); \ No newline at end of file diff --git a/script/index.html b/script/index.html new file mode 100644 index 0000000..12184f7 --- /dev/null +++ b/script/index.html @@ -0,0 +1,31 @@ + + + + + + Meta Calculator + + +

+ + + + + + + + + + + + + +
+ + + + + + + + \ No newline at end of file diff --git a/script/main.js b/script/main.js new file mode 100644 index 0000000..7fdea40 --- /dev/null +++ b/script/main.js @@ -0,0 +1,31 @@ +import {execRPN} from './shiny.mjs'; +import {parseExprs} from './parse.mjs'; +import {tokenize} from './token.mjs'; +import {scope} from './builtin.mjs'; +import './dom.mjs'; + +const tags = document.getElementsByTagName("script"); +let scripts = [] +for (let i = 0; i < tags.length; i++) { + scripts.push(tags.item(i)); +} + +scripts = scripts.filter(script => script.type === "text/rpncalc"); + +const dispatch = (src) => { + setTimeout(() => { + let http = new XMLHttpRequest(); + http.onreadystatechange = async(e) => { + if (http.readyState == 4 && http.status == 200) { + execRPN(scope, parseExprs(tokenize(http.responseText)).parsed); + } + }; + http.open("get", src); + http.responseType = "text"; + http.send(); + }, 0); +} + +for (let i = 0; i < scripts.length; i++) { + dispatch(scripts[i].src); +} \ No newline at end of file diff --git a/new/parse.mjs b/script/parse.mjs similarity index 92% rename from new/parse.mjs rename to script/parse.mjs index b576f1a..0f4a3b5 100644 --- a/new/parse.mjs +++ b/script/parse.mjs @@ -115,6 +115,19 @@ const parseType = (stream) => { //return {parsed:null, stream:stream}; } +const parseString = (stream) => { + let e = stream[0]; + if (e === undefined) { + return {parsed:null, stream:stream}; + } + if (e.type !== "string") { + return {parsed:null, stream:stream}; + } else { + stream.shift(); + return {parsed:{type:e.type, val:e.val}, stream:stream}; + } +} + /* takes in stream, outputs parsed item or null - FAILABLE */ const parsePush = (stream) => { let syn = attempt(parseSyntax("'"))(stream); @@ -161,9 +174,10 @@ const parseExpr = or( attempt(parseLambda), or( parseType, or( parseIdent, or( - parseNum, + parseNum, or( + parseString, parsePush - )))))); + ))))))); /* takes in stream, outputs parsed items */ export const parseExprs = many(parseExpr); \ No newline at end of file diff --git a/new/shiny.mjs b/script/shiny.mjs similarity index 88% rename from new/shiny.mjs rename to script/shiny.mjs index e017ba5..09fa782 100644 --- a/new/shiny.mjs +++ b/script/shiny.mjs @@ -99,7 +99,7 @@ const applyMany = (elems, state) => { } } -const makeStackElems = (ins, state, handler) => { +const makeStackElems = (ins, state) => { if (ins.type === "push") { throw 'nested push error' } else if (ins.type === "ident") { @@ -107,21 +107,21 @@ const makeStackElems = (ins, state, handler) => { } else if (ins.type === "func") { return [{type:"closure", val:{scope:state.scopes[state.scopes.length-1], args:ins.args, defn:{type:"ins", ins:ins.body}}}]; } else { - return handler(ins); + return [ins]; } } -const doIns = (ins, state, handler) => { +const doIns = (ins, state) => { if (ins.type === "push") { - state.stacks[state.stacks.length-1] = state.stacks[state.stacks.length-1].concat(makeStackElems(ins.elem, state, handler)); + state.stacks[state.stacks.length-1] = state.stacks[state.stacks.length-1].concat(makeStackElems(ins.elem, state)); } else if (ins.type === "defn") { state.scopes[state.scopes.length-1] = defn(ins.ident, ins.defn, state.scopes[state.scopes.length-1]); } else { - applyMany(makeStackElems(ins, state, handler), state); + applyMany(makeStackElems(ins, state), state); } } -const step = (state, handler) => { +const step = (state) => { if (state.calls[state.calls.length-1].length === 0) { if (state.calls.length === 1) { throw 'finished execution' @@ -136,17 +136,26 @@ const step = (state, handler) => { } else { let ins = state.calls[state.calls.length-1][0]; state.calls[state.calls.length-1] = state.calls[state.calls.length-1].slice(1); - doIns(ins, state, handler); + doIns(ins, state); } } -export const execRPN = (scope, ins, handler=(x)=>[x]) => { - let state = {scopes:[scope], stacks:[[]], calls:[ins]}; +export const exec = (state) => { while (state.calls[0].length > 0 || state.calls.length > 1) { - step(state, handler); + step(state); if (state.stacks.length > 4096) { throw 'max recursion depth exceeded' } } return state; +} + +export const execFn = (fn) => { + let state = {stacks:[[]], scopes:[fn.scope], calls:[fn.defn.ins]}; + return exec(state); +} + +export const execRPN = (scope, ins) => { + let state = {scopes:[scope], stacks:[[]], calls:[ins]}; + return exec(state); } \ No newline at end of file diff --git a/script/test.rpn b/script/test.rpn new file mode 100644 index 0000000..efacb33 --- /dev/null +++ b/script/test.rpn @@ -0,0 +1,45 @@ +(output; `out` getId) + +(acc; 0 mutref) +(stack; 0 tuple mutref) + +(show; '(-> + output acc readmut "string coerce setHTML)) + +(writeDigit; x -> + acc readmut 10 * x + acc writemut show) + +(spush; stack val -> + stack untuple val stack len 1 + tuple) + +(push; '(-> + stack readmut acc readmut spush stack writemut)) + +(spop; stack -> + stack untuple (a ->) stack len 1 - tuple) + +(last; stack -> + stack stack len 1 - !!) + +(pop; '(-> + stack readmut last stack readmut spop stack writemut)) + +(b1; `1` getId) b1 '(->1 writeDigit) onclick +(b2; `2` getId) b2 '(->2 writeDigit) onclick +(b3; `3` getId) b3 '(->3 writeDigit) onclick +(b4; `4` getId) b4 '(->4 writeDigit) onclick +(b5; `5` getId) b5 '(->5 writeDigit) onclick +(b6; `6` getId) b6 '(->6 writeDigit) onclick +(b7; `7` getId) b7 '(->7 writeDigit) onclick +(b8; `8` getId) b8 '(->8 writeDigit) onclick +(b9; `9` getId) b9 '(->9 writeDigit) onclick +(b0; `0` getId) b0 '(->0 writeDigit) onclick + +(bpush; `push` getId) bpush '(->push 0 acc writemut show) onclick +(bpop; `pop` getId) bpop '(->pop acc writemut show) onclick +(bzero; `zero` getId) bzero '(->0 acc writemut show) onclick + +(badd; `add` getId) badd '(->pop pop + acc writemut show) onclick +(bsub; `sub` getId) bsub '(->pop pop (a b -> b a) - acc writemut show) onclick +(bmul; `mul` getId) bmul '(->pop pop * acc writemut show) onclick +(bdiv; `div` getId) bdiv '(->pop pop (a b -> b a) / acc writemut show) onclick \ No newline at end of file diff --git a/script/token.mjs b/script/token.mjs new file mode 100644 index 0000000..036e8c1 --- /dev/null +++ b/script/token.mjs @@ -0,0 +1,68 @@ +const tokens = (stream) => { + let toks = []; + let currTok = {val:"", type:"str"}; + let stringmode = false; + for (let i = 0; i < stream.length; i++) { + if (stringmode) { + if (stream[i] === '`') { + toks.push(currTok); + stringmode = false; + currTok = {val:"", type:"str"}; + } else { + currTok.val += stream[i]; + } + } else if (stream[i] === '`') { + if (currTok.val !== "") { + toks.push(currTok); + } + stringmode = true; + currTok = {val:"", type:"string"}; + } else if ("()';\"".includes(stream[i])) { + if (currTok.val !== "") { + toks.push(currTok); + } + toks.push({val:stream[i], type:"syntax"}); + currTok = {val:"", type:"str"}; + } else if (stream[i] === "-") { + if (stream[i+1] === ">") { + if (currTok.val !== "") { + toks.push(currTok); + } + toks.push({val:"->", type:"syntax"}); + i++; + currTok = {val:"", type:"str"}; + } else { + currTok.val += "-"; + } + } else if (/\s/.test(stream[i])) { + if (currTok.val !== "") { + toks.push(currTok); + } + currTok = {val:"", type:"str"}; + } else { + currTok.val += stream[i]; + } + } + if (currTok.val !== "") { + toks.push(currTok); + } + return toks; +} + +const classify = (tokens) => { + return tokens.map(tok => { + if (tok.type === "str") { + if (!isNaN(tok.val)) { + return {val:Number(tok.val), type:"num"}; + } else { + return {name:tok.val, type:"ident"}; + } + } else { + return tok; + } + }); +} + +export const tokenize = (stream) => { + return classify(tokens(stream)); +} \ No newline at end of file diff --git a/tracer/index.html b/tracer/index.html index 33e1363..ce63583 100644 --- a/tracer/index.html +++ b/tracer/index.html @@ -18,7 +18,7 @@ code {

 

 
-

Documentation

+

documentation

use (name; value) to define something. the definition can be recursive. value is executed and name is set to the final state of the stack, i.e. (name; 1 3) is possible

use ' to push instead of apply to the stack, e.g. '(a -> a). This is useful for lazyness, i.e. '(->lazy evaluated thing)

    @@ -29,10 +29,17 @@ code {
  • tuple: used like ... 3 tuple; creates an n tuple of n items on the stack
  • !!: index into a tuple
  • len: length of a tuple
  • -
  • unsafeCoerce: unsafely transforms one type into another. useage: 1 "type unsafeCoerce
  • -
  • true, false: true/false used in ==
  • -
  • stop: equivalent to "stop
  • -
  • inv: equivalent to 1 x /
  • -
  • fold: equivalent to x acc fn -> acc '(-> x acc fn 'fn fold) 'x \"stop ==
  • +
+

stdlib

+
    +
  • stop; "stop
  • +
  • inv; x -> 1 x /
  • +
  • fold; x acc fn -> acc '(-> x acc fn 'fn fold) 'x \"stop ==
  • +
  • range; x y -> x '(->x x 1 + y range) 'x y ==
  • +
  • listthen; fn -> (internal; x acc -> '(->acc fn) '(->x acc pair internal) x stop ==) 0 tuple internal
  • +
  • list; (a -> a) listthen
  • +
  • lmap; list fn -> list '(->list fst fn list snd 'fn lmap pair) list 0 tuple ==
  • +
  • unlist; l -> (internal; list -> '(->) '(->list fst list snd internal) list 0 tuple ==) stop l internal
  • +
  • map; fn -> '(l->l 'fn lmap unlist) listthen
\ No newline at end of file