This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

mlang / README.md
6.3 kB 182 lines
1# mlang 2 3A small functional language prototype written in Lean 4. 4 5Current scope: 6 7- integer, decimal, and boolean literals 8- variables 9- `let` 10- `if` 11- typed lambdas 12- function application 13- decimal arithmetic with implicit `Int` promotion 14- strings 15- native parsed data values 16- lexical closures 17- hand-written lexer and parser 18- static type checker 19- implicit effect tracking 20- builtin file IO 21- builtin Nickel evaluation 22 23The interpreter lives in [Mlang/Interpreter.lean](/home/nandi/code/mlang/Mlang/Interpreter.lean:1). 24The parser lives in [Mlang/Parser.lean](/home/nandi/code/mlang/Mlang/Parser.lean:1). 25 26## Run 27 28With `devenv` installed: 29 30```bash 31devenv shell 32build 33run 34``` 35 36You can also run commands directly without entering the shell: 37 38```bash 39devenv test 40devenv shell -- build 41devenv shell -- run 42``` 43 44The executable supports a REPL and file execution: 45 46```bash 47devenv shell -- lake exe mlang 48devenv shell -- lake exe mlang --eval "1 + 2" 49devenv shell -- lake exe mlang examples/samples.mlg 50``` 51 52Current syntax: 53 54```text 55expr ::= let name = expr in expr 56 | if expr then expr else expr 57 | try expr with name => expr 58 | pmap name in expr => expr 59 | -> expr ident* 60 | fun (name : type) => expr 61 | expr = expr 62 | expr + expr 63 | expr - expr 64 | expr * expr 65 | expr expr 66 | [expr, ...] 67 | { key = expr, ... } 68 | null 69 | (expr) 70 | true | false | 123 | 1.23 | "text" | name 71 72program ::= expr (';' expr)* 73 74type ::= Int | Decimal | LazyReal | Bool | String | Data | List | Result | Error | type -> type | (type) 75``` 76 77Inside the REPL, there is also a top-level binding form: 78 79```text 80repl ::= let name = expr 81``` 82 83Bare REPL bindings persist across later entries, so you can write: 84 85```mlang 86let x = 42 87x + 1 88``` 89 90Expressions are checked as `Type ! Effects`. Plain numeric literals now default to `Rational`, so `1`, `1.25`, `1 + 2`, and `5 / 2` are all rational values unless you explicitly cast them. Division carries `{Error}` implicitly. `readFile` is a builtin with type `String -> String ! {IO, Error}`. `readFileNickel` is a builtin with type `String -> Data ! {IO, Error}`. `parseNickel` is a builtin with type `String -> Data ! {Error}` and is backed by the real Nickel Rust crate. Nickel source is evaluated on the host side and converted back into `mlang` `Data`. Parsed data inspection is available through: 91 92- `httpGet : String -> String ! {IO, Error}` 93- `parseJson : String -> Data ! {Error}` 94 95- `get : Data -> String -> Data ! {Error}` 96- `at : Data -> Rational -> Data ! {Error}` 97- `asInt : Data -> Int ! {Error}` 98- `asDecimal : Data -> Decimal ! {Error}` 99- `asString : Data -> String ! {Error}` 100- `asBool : Data -> Bool ! {Error}` 101- `toInt : Rational -> Int ! {Error}` 102- `toDecimal : Rational -> Decimal ! {Error}` 103- `toJson : Data -> String` 104- `toNickel : Data -> String` 105- `rationalStability : Rational -> Stability` 106- `decimalStability : Rational -> Stability` 107- `sqrt : Decimal -> LazyReal ! {Error}` 108- `pi : LazyReal` 109- `lazyRationalStability : LazyReal -> Stability` 110- `lazyDecimalStability : LazyReal -> Stability` 111- `approx : LazyReal -> Rational -> Rational ! {Error}` 112- `bounds : LazyReal -> Rational -> Data ! {Error}` 113 114`httpGet` is implemented through a thin Rust host library plus a small C shim for Lean FFI. The Rust layer uses a real HTTP client crate rather than spawning an external tool. 115`try ... with name => ...` handles `Error`, binds the caught error as an `Error` value, and removes `Error` from the resulting effect set when recovered locally. 116 117The host-side Nickel bridge currently maps evaluated Nickel values back into `mlang` data for: 118- `null` 119- booleans 120- integers 121- decimals 122- strings 123- arrays 124- records 125 126Exact rational values are supported in native literals and in `Data` values coming from JSON or Nickel. 127 128Native `Data` literals are also supported directly in `mlang`: 129 130```mlang 131{ answer = 42, flags = [true, false], note = "ok", empty = null } 132``` 133 134Fields and array elements may be `Rational`, `Bool`, `String`, or existing `Data` expressions. 135 136`LazyReal` represents process-like numeric values that are observed through refinement. The current implementation supports decimal input to `sqrt`, while `approx` and `bounds` observe lazies as rationals: 137 138```mlang 139let r = sqrt 2.0 140approx r 4 141bounds r 4 142approx pi 4 143toDecimal (approx pi 4) 144``` 145 146Ordinary arithmetic lifts over `LazyReal`, so expressions like `sqrt 2.0 + 3.0` stay lazy until observed with `approx` or `bounds`. 147 148Stability observations classify how a number settles under rational and decimal observation: 149 150```mlang 151rationalStability (1 / 3) -- Immediate 152decimalStability (1 / 3) -- Periodic 153lazyRationalStability pi -- Refining 154lazyDecimalStability (sqrt 2) -- Refining 155``` 156 157`pmap name in expr => body` expects `expr` to evaluate to a native `Data` array. It evaluates `body` concurrently for each element bound to `name`, preserves input order, and returns a native `List` of native `Result` values instead of failing the whole traversal. 158 159There is also a thread-first form that desugars statically to nested application: 160 161```mlang 162-> "examples/sample.ncl" readFileNickel (get "answer") 163``` 164 165Parallel collection mapping example: 166 167```mlang 168pmap x in parseNickel "[{ answer = 1 }, { missing = 2 }, { answer = 3 }]" 169 => get x "answer" 170``` 171 172Files and REPL entries may contain multiple expressions separated by `;`. Each expression is parsed, typechecked, evaluated, and printed in order. REPL-specific bare `let` bindings persist across later entries. `devenv shell -- run` now launches a Rust `rustyline` frontend for the REPL, while the Lean binary still handles evaluation. Use `:quit` to exit the REPL. 173 174The checked-in sample program is [examples/samples.mlg](/home/nandi/code/mlang/examples/samples.mlg:1), which now contains the old demo coverage as semicolon-separated expressions, including file IO, Nickel parsing, threading, `pmap`, local error handling, and an HTTP fetch. It reads from [examples/sample.ncl](/home/nandi/code/mlang/examples/sample.ncl:1). 175 176A separate HTTP example is [examples/http.mlg](/home/nandi/code/mlang/examples/http.mlg:1). 177 178## Next steps 179 180- add recursive functions 181- add algebraic data types and pattern matching 182- compile to a bytecode VM or another backend