Wipple updates
Wipple
I haven’t pushed to the wipplelang/wipple repository lately, but I am experimenting around with some new ideas privately. I’ve been working on some quality-of-life improvements to Wipple — check them out!
-
Statements are now separated with a newline instead of a semicolon. Statement breaks will occur when all preceding statement items are parsed (ie. no open groups) and a newline is encountered:
foo -- one statement bar -- another statement (foo bar baz ) -- one statement
The last statement in a block is still the one returned, and empty blocks still evaluate to the empty list.
-
Statements are now just lists — there is no distinct type. The semantics for lists are altered so a single-item list is evaluated as if that item was not in a list:
(foo bar) -- call 'foo' with 'bar' (foo bar baz) -- call 'foo' with 'bar', and the result with 'baz' (foo) -- evaluate 'foo' () -- return as-is
-
Lists with operators are now parsed so they consume all values on both sides until an operator of a higher precedence is reached. This removes the need for explicit lists in many places:
bob : person (| age 42 |)
In previous versions of Wipple extra parentheses would be required:
bob : (person (| age 42 |))
Note that if the operator’s function evaluates the parameter before returning, and the left-hand- and/or right-hand-side of the operator contains only one value, the single value will be used congruent to the changes in list evaluation above.
-
If an operator is evaluated on its own, the function the operator wraps is returned instead of the operator itself (which is unusable alone):
> + function -- the 'add' function
In previous versions of Wipple:
> + operator -- the '+' operator
-
Added
pairlist
, a primitive that groups pairs of values. Pair lists are almost always used with another function, likestruct
or keyed functions. The syntax is(| a b c d |)
, which will create a pair list with two pairs,'a b
and'c d
(ie. the first item in the pair is left unevaluated and the second item is evaluated).For example, pair lists are used by
struct
s to associate values with property names:person : struct (| name "Bob" age 42 favorite-color 'blue |)
In order to evaluate the first pair item as well, you can pass the pair list to the
dynamic
package’seval-pairlist-keys!
:> a : 1 () > b : 2 () > c : 3 () > d : 4 () > (| a b c d |) pairlist > list (| a b c d |) -- need to convert to list to view in wipple ((a 1) (c 4)) > use dynamic () > (| a b c d |) |> eval-pairlist-keys! |> list ((1 2) (3 4))
-
Dot syntax has been removed at the parser level; it is now an operator:
foo . bar -- access the 'bar' property on the value of 'foo'
Because dot syntax was the only thing requiring the
Property
trait from being built-in, this trait is now implemented in theproperty
package (which thestruct
package uses as a dependency). TheProperty
trait looks like this:Property : trait (name -> value -> (Data (| name name value value |)) )
And the
.
operator is defined like this:dot-precedence : 100 . : operator (| precedence dot-precedence associativity left call (base => 'prop => ...) |)
Note that the
.
operator evaluates the left-hand side for each call. This will probably lead to unexpected behavior if you try chaining.
calls:a : struct (| b '(c d) |) -- expected: c -- actual: error (c is not defined) a . b . 0 -- this is because (c d) is evaluated again after being returned. -- above is evaluated like this: (a . b) . 0 (c d) . 0 error: c is not defined in (c d) (file.wpl:12:2) ...
What you probably want to do is use the
..
operator, which accepts a list of paths to be applied one after the other:> a .. b 0 c
And if you want to do this dynamically, you can use the
dynamic
package’sresolve-path!
function:> use dynamic () > path-segment-1 : 'b () > path-segment-2 : 1 - 1 () > resolve-path! a [path-segment-1 path-segment-2] c
-
...
has been added to the standard library and serves as a placeholder so that incomplete examples can still run. It evaluates to itself:... : '...