|
| 1 | +--- |
| 2 | +title: Philosophy |
| 3 | +description: The ideas behind Lambda Discipline, and why the language looks the way it does. |
| 4 | +--- |
| 5 | + |
| 6 | +# Philosophy |
| 7 | + |
| 8 | +> A language should be small enough to hold in your head, and strict enough |
| 9 | +> that what you hold there is true. |
| 10 | +
|
| 11 | +Lambda Discipline begins with the lambda calculus, the smallest language that |
| 12 | +can express any computation: variables, functions of one argument, and |
| 13 | +application. Everything else is there to make that core pleasant to write and |
| 14 | +safe to run. Where convenience and coherence disagree, coherence wins. |
| 15 | + |
| 16 | +## The lambda is the unit of thought |
| 17 | + |
| 18 | +There are no statements, no loops and no special forms. A program is |
| 19 | +definitions and applications of `\x. body` functions, and each application is |
| 20 | +an S-expression whose shape *is* its meaning: `(f x y)` applies `f` to `x`, |
| 21 | +then to `y`. A grammar this small has no corners to memorize. You learn it once |
| 22 | +and then think only about your problem. |
| 23 | + |
| 24 | +Functions take one argument at a time, so partial application is free. The |
| 25 | +builtins are designed for it: the data a function works on always comes last, |
| 26 | +which makes `(map (add 1))`, `(filter (lt 0))` and `(split ",")` complete, |
| 27 | +meaningful functions on their own. |
| 28 | + |
| 29 | +## Discipline means types |
| 30 | + |
| 31 | +The *discipline* is the type system. Every program is checked with |
| 32 | +Hindley-Milner inference before a single expression runs, and a program that |
| 33 | +doesn't type-check doesn't run. There are no warnings to ignore. |
| 34 | + |
| 35 | +Inference keeps the discipline from becoming bureaucracy. You write |
| 36 | +annotations where they say something useful to a reader, and the checker works |
| 37 | +out the rest, always finding the most general type. When you do write an |
| 38 | +annotation, it is a contract: its type variables are rigid, so a function |
| 39 | +can't quietly claim to be more general than it is. |
| 40 | + |
| 41 | +## Laziness is the honest default |
| 42 | + |
| 43 | +Arguments are evaluated when they are needed, and only once. With laziness, |
| 44 | +`if`, `and` and `or` need no special treatment: they are ordinary functions |
| 45 | +that simply don't touch the branch they don't take. Control flow is just |
| 46 | +another thing you can define, pass around and partially apply. |
| 47 | + |
| 48 | +Laziness asks for a runtime that respects it, so tail calls run in constant |
| 49 | +space, deep recursion is bounded by memory rather than a fixed stack, and a |
| 50 | +value that depends on itself is reported instead of hanging. |
| 51 | + |
| 52 | +## Values don't change |
| 53 | + |
| 54 | +Lists are immutable persistent vectors. Adding, removing or reading an element |
| 55 | +returns a new list in logarithmic time and leaves the original exactly as it |
| 56 | +was. A name means one thing for its whole life, which is what makes laziness, |
| 57 | +sharing and equational reasoning safe. |
| 58 | + |
| 59 | +## Errors are part of the interface |
| 60 | + |
| 61 | +A language is used mostly while it is telling you that you're wrong. Lambda |
| 62 | +Discipline reports every independent error it finds in one run, points at the |
| 63 | +exact code responsible, and suggests the name you probably meant. Runtime |
| 64 | +errors point at the call that failed. Nothing crashes with a stack trace from |
| 65 | +the implementation. |
| 66 | + |
| 67 | +## Built like a compiler |
| 68 | + |
| 69 | +Under the interpreter is a conventional compiler pipeline, the shape of rustc |
| 70 | +or GHC: a lexer and parser, name resolution, type inference, and a Core IR that |
| 71 | +is closure-converted and uncurried. Today that IR feeds a lazy abstract |
| 72 | +machine. Tomorrow it can feed a transpiler, a virtual machine or native code |
| 73 | +without the front end changing. Builtins are declared once, with their type and |
| 74 | +documentation, and every stage reads that one declaration. The |
| 75 | +[builtin reference](/builtins/) on this site is generated from it. |
| 76 | + |
| 77 | +## Free to improve |
| 78 | + |
| 79 | +Lambda Discipline is young, and it isn't bound by compatibility with its own |
| 80 | +past. Its current implementation is a ground-up rewrite that renamed builtins, |
| 81 | +tightened the type system and changed the syntax wherever doing so made the |
| 82 | +language more coherent. It will keep doing that while it's young. |
0 commit comments