Something I've finally taken to serious prototyping recently is some iteration/looping syntax for a more distant Harlowe release. As you may know, I've been steering Harlowe in an FP direction, avoiding imperative forms as much as possible (such that various data structure methods are named for declarative adjectives rather than verbs - (shuffled:), (sorted:) etc.). In that vein, the basic looping constructs I'm providing to Harlowe currently look like this:
is a generalised form of the aforementioned (shuffled:), (sorted:) macros. It accepts multiple values to convert and express as an array, but also accepts a transformer statement, which looks something like "each _data to _data + 1
" or "each _itemname to "This item is: " + _itemname
". The statement describes what to do to each
of the values to make the new array. Some examples:
(converted: each _person to _person + (datamap: 'status', 'poisoned'), ...$people)
copies every element in the $people array (which I assume contains datamaps of people), but with their 'status' changed to 'poisoned'.
(converted: each _num to (random:0,10), ...(range:1,10))
creates an array of 10 random single-digit numbers.
creates a smaller array from several values, by excluding those which don't match a specific clause statement. Clause statements look like "each _person where _person's HP > 0
" or "each _name where $hostageName is not _name
". Some examples:
(filtered: each _person where _person's status is 'poisoned', ...$people)
produces an array of the $people whose status is poisoned.
(filtered: each _person where (either:1,2) is 2, ...$people)
produces a random subarray of $people
I'm contemplating renaming this to (find-all:), and inverting the clause from exclusion to inclusion, on the basis that people understand "searching" better than "filtering".
is one that I'm a bit less sure of. It's like (converted:), except you provide a two-value transformer statement which resembles "each _total, _item to _total + _item's price
" or "each _currentBiggest, _item to (max: _currentBiggest, _item)
". The first value, the "total", equals the previous iteration's value (or the first value, at the start) and the next one is te current passed value (or the second value, at the start), and you specify how to combine each value with the total. Some examples:
(combined: each _text, _person to _text + "Name: " + _person's name + "; Age: " + _person's age + "<br>", ...$people)
Produces a text string listing each person's name and age. You could perhaps think of this as the equivalent of a for-print loop in an imperative language.
The reason I'm unsure about this one is that the placement of the "each" keyword kind of doesn't work here (really, it should read more like "each _item, with _total, to _total + _item's price
") and also by the fact that this requires some inductive thinking to properly understand (the idea of expressing a loop in terms of what a single iteration does, relative to its previous iteration) which may be a cognitive load too weighty to bear.
Any thoughts on these are welcome.