Skip to content

Commit a31b6dc

Browse files
committed
Add lambdas to README
1 parent cd2b19e commit a31b6dc

1 file changed

Lines changed: 64 additions & 18 deletions

File tree

README.md

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ constitutes a `StringLang` source file. The complete grammar can be found in `la
6666

6767
```
6868
identifier: any string of alphanumeric and underscore characters not beginning with a digit
69-
number: positive integer
70-
string_literal: a "double-quoted" string, containing any sequence of characters
71-
comment: /* any text enclosed by /* and */, except '/*' and '*/' */
69+
number: non-negative integer
70+
string_literal: a "double-quoted" string, containing any sequence of characters, escapes allowed using '\'
71+
comment: any text enclosed by /* and */, except '/*' and '*/' (no nested comments)
7272
7373
7474
program:
@@ -90,7 +90,7 @@ expression:
9090
$number
9191
expression[expression]
9292
expression[number]
93-
identifier(expression1, expression2, ..., expressionN) // N can be 0
93+
expression(expression1, expression2, ..., expressionN) // N can be 0
9494
9595
expression || expression
9696
expression && expression
@@ -103,12 +103,17 @@ expression:
103103
ifelse
104104
while
105105
106+
lambda
107+
106108
ifelse:
107109
if (expression) { block } else { block }
108110
if (expression) { block } else ifelse // This effectively allows else-if
109111
110112
while:
111113
while (expression) { block }
114+
115+
lambda:
116+
fun(param1, param2, ..., paramN) { block } // paramX are identifiers, N may be 0
112117
```
113118

114119
### Caveats
@@ -127,14 +132,52 @@ All expressions/values in `StringLang` are Strings.
127132
### Functions
128133

129134
Functions in `StringLang` can either be user-defined (i.e. they are written in `StringLang` and reside
130-
in the header of the interpreted file), or they can be built-in (i.e. supplied to the interpreter
131-
via the context, see the Context section). Because built-in functions are written in Go, they can accomplish anything
132-
Go can accomplish.
135+
as a top-level function in the header of the interpreted file, or are lambdas), or they can be built-in
136+
(i.e. supplied to the interpreter via the [context](#context-functions-and-arguments)).
137+
Because built-in functions are written in Go, they can accomplish anything Go can accomplish.
133138

134139
User-defined `StringLang` functions are evaluated with their own completely separate variable scope and
135140
are mutually recursive. The arguments passed to them are bound to the variables in the corresponding parameter lists.
136141

137-
All functions in `StringLang` are pass-by-value.
142+
All functions in `StringLang` are pass-by-value, hence also strict.
143+
144+
#### Calls
145+
146+
In a `expr(args...)` call, finding the function corresponding to `expr` has the following order:
147+
1. Check if `expr` is an `identifier` equal to some `f` and that there exists a *top-level, user-defined* function
148+
`fun f(params) { block }`, if so, call that function.
149+
2. Check if `expr` is an `identifier` equal to some `f` and that there exists a *built-in*
150+
function that is mapped to that `f` in the provided [context](#context-functions-and-arguments), if so, call that.
151+
3. If `expr` is not an `identifier` with corresponding named function, then [evaluate](#evaluation) `expr` and treat the
152+
resulting String as source code of a `lambda`, then call that lambda.
153+
154+
#### Lambdas
155+
156+
Lambdas in StringLang capture their environment by-value, and encode it as simple assignments at the top of the `block`.
157+
Evaluating them (which is different to calling them) results in a canonical source representation of the lambda.
158+
159+
Example: The expression `fun(x) { x + y }` is evaluated differently depending on its context. In particular,
160+
the run-time value of the `identifier` `y` will be copied into the block, e.g. assuming `y` evaluates to `"value"`
161+
in the current context the lambda becomes: `fun(x) { y = "value"; x + y }`, a context-insensitive lambda. Now it can
162+
be evaluated into a String and returned:
163+
```
164+
"fun(x) {
165+
y = \"value\";
166+
x + y
167+
}"
168+
```
169+
At the site of a [call](#calls), this String can now be interpreted as the source code of a lambda, and called as such.
170+
Note that because we stored the value of `y` inside the lambda, the context in which we call this "lambda-turned-String"
171+
does not matter.
172+
173+
Also note that lambdas are still user-defined functions, which are evaluated using a separate variable scope. Hence the
174+
`y = "value"` in the block will not cause the caller's `y` to be set to `"value"`.
175+
176+
If you need more examples, see [lambdas.stringlang](stringlang_programs/lambdas.stringlang) or
177+
[ski_combinator.stringlang](stringlang_programs/ski_combinator.stringlang) to see how the SK-calculus looks like in
178+
StringLang.
179+
180+
138181

139182
### Binary Operators
140183

@@ -153,24 +196,27 @@ The following list gives the binary operators, ordered from low to high preceden
153196

154197
### Evaluation
155198
```
156-
string_literal The value of 'string_literal'
157-
identifier The current value of the variable with identifier 'identifier'.
158-
identifier = expression The value of 'expression'.
199+
string_literal ------------ The value of 'string_literal'
200+
identifier ---------------- The current value of the variable with identifier 'identifier'.
201+
identifier = expression --- The value of 'expression'.
159202
Side effect: Variable 'identifier' now has that value.
160-
$number The value of the 'number'-th (zero-indexed) argument to the program.
161-
expr1[expr2 or number] The character at position 'expr2' resp. 'number' of the value
203+
$number ------------------- The value of the 'number'-th (zero-indexed) argument to the program.
204+
expr1[expr2 or number] ---- The character at position 'expr2' resp. 'number' of the value
162205
that 'expr1' evaluates to.
163-
identifier(expr1, ...) Function call to function 'identifier' with arguments 'expr1, ...'.
206+
expr(expr1, ...) ---------- Function call to function 'expr' (See 'Functions' section) with arguments 'expr1, ...'.
164207
Arguments are evaluated before passed to the function.
165208
Evaluates to the function's return value.
166-
expr1 <binop> expr2 The value of the corresponding binary operation.
209+
expr1 <binop> expr2 ------- The value of the corresponding binary operation.
167210
168-
ifelse The value of the then-block if the condition evaluates to a true value,
211+
ifelse -------------------- The value of the then-block if the condition evaluates to a true value,
169212
or the value of the else-block if the condition evaluates to a false value.
170-
while The value of the last iteration of the block if it gets executed once, else "".
213+
while --------------------- The value of the last iteration of the block if it gets executed once, else "".
171214
Side effects: All iterations might cause side effects
172215
173-
block The value of the last expression in the block.
216+
lambda -------------------- The canonical source representation of the whole lambda as string, but with the blocks's
217+
used variables captured by-value in the lambda.
218+
219+
block --------------------- The value of the last expression in the block.
174220
Side effects: Evaluates all expressions in the list.
175221
176222
```

0 commit comments

Comments
 (0)