<!doctype html> <html> <head> <title>CodeMirror: Lambda Calculus mode</title> <meta charset="utf-8"/> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.1/codemirror.min.css"> <link rel="stylesheet" href="./theme/codewars.css"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro"> <link rel="stylesheet" href="https://unpkg.com/awsm.css@3.0.7/dist/awsm_theme_black.min.css"> <style> .CodeMirror { border-top: 1px solid black; border-bottom: 1px solid black; } [v-cloak] { display: none !important; } </style> </head> <body class="dark"> <header class="!mb-0"> <h1> <a href="https://github.com/codewars/lambda-calculus" title="Lambda Calculus"> <img alt="Lambda Calculus" src="https://raw.githubusercontent.com/codewars/lambda-calculus/main/logo/logo-white.svg" width="64" height="64"> </a> <p class="mt-4 text-2xl text-center">Lambda Calculus mode for CodeMirror</p> </h1> <p class="text-center"><code>text/x-lambdacalc</code></p> <p class="text-center"><a href="https://github.com/codewars/codemirror-lambda-calculus">@codewars/codemirror-lambda-calculus</a></p> </header> <main class="mt-6" v-scope> <form> <textarea id="code"> # Ignored arguments false = \ _a b . b true = \ a _b . a not = \ b . b false true const = true # Multiple definition true = not false # Invalid whitespace (tabs) whitespace = () # Bare lambda (\ f x . f (x x)) # Bare term const f x # Symbols < a b c > => < a a a > # Unbound some-func = \ local . true non-existent local # Out of scope args other-func = \ x . const (\ scoped-arg . x ()) scoped-arg x # Debug mode on #debug # Invalid names - Debug %value = () # Bare lambda - Debug (\ f x . f (x x)) # Bare term - Debug const f x # Symbols - Debug < a b c > => < a a a > # Unbound - Debug some-func = \ local . true non-existent local # Out of scope args - Debug other-func = \ x . const (\ scoped-arg . x ()) scoped-arg x # Debug mode off #debug # More code zero = false succ = \ n f x . f (n f x) is-z = \ n . n (const false) true add = \ a b f x . a f (b f x) mul = \ a b f . a (b f) three = succ (succ (succ zero)) mt = mul three nine = mul three three pair = \ a b c . c a b fst = \ c . c true snd = \ c . c false nil = pair false () null = \ l . not (fst l) head = \ l . fst (snd l) tail = \ l . snd (snd l) cons = \ x xs . pair true (pair x xs) replicate = \ n v . n (cons v) nil repeat = \ v . cons v (repeat v) foldr = \ f b as . null as b (f (head as) (foldr f b (tail as))) pred = \ n f x . foldr (const f) x (tail (replicate n ())) # Bit janky lol map = \ f xs . null xs nil (cons (f (head xs)) (map f (tail xs))) sum = foldr add zero drop = \ n . n tail take = \ n xs . is-z n nil (cons (head xs) (take (pred n) (tail xs))) col = \ n xs . head (drop n xs) colS = \ n xs . cons (col n xs) (cons (col (succ n) xs) (cons (col (succ (succ n)) xs) (nil))) row = \ n xs . map (col n) xs row-s = \ n xs . cons (row n xs) (cons (row (succ n) xs) (cons (row (succ (succ n)) xs) (nil))) chunk = \ a b xs . row-s a (colS b xs) append = \ as bs . null as bs (cons (head as) (append (tail as) bs)) concat = foldr append nil eq? = \ a b . is-z a (is-z b) (is-z b false (eq? (pred a) (pred b))) all = foldr (\ a b . a b false) true allf = \ f xs . all (map f xs) </textarea> </form> <div class="mx-auto mt-8 w-96 grid grid-flow-row grid-cols-4 grid-rows-2 gap-1"> <input type="text" v-model="evaluation" @keyup.enter="evaluate()" class="col-span-3" /> <button @click="evaluate()" class="col-span-1">Evaluate</button> <code v-cloak class="px-2 py-1 mt-1 col-span-4 bg-white/10" v-show="result">{{ result }}</code> <code v-cloak class="px-2 py-1 mt-1 col-span-4 bg-red-800/60" v-show="error">{{ error }}</code> </div> <div class="mx-auto mt-4 w-80"> <fieldset> <legend>Options</legend> <div class="grid grid-cols-2 grid-rows-3 gap-1"> <label class="!m-0" for="purity"><code>purity</code></label> <select id="purity" v-model="purity"> <option v-for="opt in purityOptions" :value="opt" :selected="opt === purity">{{ opt }}</option> </select> <label class="!m-0" for="num-encoding"><code>numEncoding</code></label> <select id="num-encoding" v-model="numEncoding"> <option v-for="opt in numEncodingOptions" :value="opt" :selected="opt === numEncoding">{{ opt }}</option> </select> <label class="!m-0" for="verbosity"><code>verbosity</code></label> <select id="verbosity" v-model="verbosity"> <option v-for="opt in verbosityOptions" :value="opt" :selected="opt === verbosity">{{ opt }}</option> </select> </div> </fieldset> </div> </main> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.1/codemirror.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.1/addon/edit/matchbrackets.min.js"></script> <script type="module"> import "virtual:windi.css"; import { createApp } from "https://unpkg.com/petite-vue@0.4.1?module"; import * as LC from "https://unpkg.com/@codewars/lambda-calculus"; import { defineMode } from "./lambdacalc.js"; defineMode(CodeMirror); const editor = CodeMirror.fromTextArea(document.getElementById("code"), { mode: "lambdacalc", lineNumbers: true, matchBrackets: true, theme: "codewars", specialChars: /\\/, specialCharPlaceholder: () => { const elem = document.createElement("span"); elem.setAttribute("cm-text", "\\"); elem.innerHTML = "λ"; return elem; } }); editor.setSize(500, 400); const toLambda = (s) => s.replace(/\\/g, "λ"); createApp({ purity: "Let", purityOptions: ["Let", "LetRec", "PureLC"], verbosity: "Calm", verbosityOptions: ["Calm", "Concise", "Loquacious", "Verbose"], numEncoding: "Church", numEncodingOptions: ["None", "Church", "Scott", "BinaryScott"], evaluation: "not false", result: "", error: "", evaluate() { this.result = ""; this.error = ""; const code = editor.getValue(); const val = this.evaluation; const compile = LC.compileWith({ purity: this.purity, verbosity: this.verbosity, numEncoding: this.numEncoding, }); try { const { result } = compile(`${code}\n\nresult = ${val}`); this.result = toLambda(result.term + ""); } catch (e) { this.error = e.message || e.name; } }, }).mount(); </script> </body> </html>