I guess you prefer general settings over function parameters in order to keep it simple for beginners - didn’t we discuss this before, in a different topic? (Please keep reading, I have a solution in mind).
I tend to disagree with you on this. IDENTICAL TO is very much an interpretation advanced users may want to apply, and only in some special cases; a general setting is like a nuclear bomb where tweezers are needed.
If you must use a general setting, ask Jens if he could create a setting to control whether optional function parameters be visible (and changeable, of course) - so beginners will not be confronted with those, and everyone will be happy (ever after ).
We already have that for some blocks, such as BROADCAST and ASK. But we started down that road with some hesitancy, because we think that users may find it intimidating. I'd prefer not to have huge families of blocks (everything that does a comparison, e.g., CONTAINS) be loaded with optional inputs. (You could imagine a deep/shallow option for CONTAINS, for example.)
IDENTICAL TO is for special cases if you reject the idea of worrying about speed. But if you're doing media computation, and so you're constantly tinkering with the pixels of a costume, for example, then it's a big win if you can get away with IDENTICAL TO.
Historically, Lisp solved this problem as you suggest, with optional inputs, but only after it developed keyword inputs that aren't dependent on being in a particular order. (foo bar baz &compare: eq) There could be a dozen optional inputs and you wouldn't have to know about any but the one you want. That's harder for us to invent in a visual language.
In both versions the base case should be
IF (IS DATA EMPTY?) OR (IS (ALL BUT FIRST OF DATA) EMPTY?)
If the list is stored as a dynamic array, you can check IF (LENGTH OF DATA) < 2 instead, but for linked lists that'll make the whole thing take quadratic time.
Then, just a typo, you meant to call the recursive version as the recursive call, not the HOF version!
Your HOF code gives me a headache, trying to figure out which elements it's checking in the CONTAINS. Seems to me it should always have to report True. I'd rather write the HOF version to keep the rightmost instance of a value rather than the leftmost:
<(ITEM (NUMBERS FROM (INDEX+1) TO (LENGTH OF DATA)) OF DATA) CONTAINS VALUE>
The logic is just like yours, except that it examines the part of the list from which you haven't eliminated any values yet, thereby not giving me a headache. :~)
My version works as well, but both versions may take some time to execute for long lists. The following "improved" version is more complicated but very fast both for an empty list, a list of 1 item, and longer lists:
The second (fast) predicate doesn't always work (try ) so I added the third to make the whole thing foolproof (and still fast except for exotic cases).
This base case (report data if empty or length = 1) is quite common in recursive functions, almost worth a separate primitive (even though I wouldn’t know how to code it, with a macro perhaps?).
Remedies can be found at any pharmacy ... OK, I made an easier-to-grasp alternative (see below).
A new set of alternatives for [uniques] OF ()
all results with Case sensitivity = OFF
The HOF-implementation has one downside: every item will be compared to all preceding items, even if not all of these are unique. This is easily improved by a recursive version:
The above recursive implementation however keeps the last of any equal items. If the order of the output is important, and keeping the first of equal items is prefered, the next version will take care of that. It's somewhat more complicated, of course.
The HOF-implementation is usually faster than the "keep first item"-version of the recursive implementation; while the latter is always faster than recursive "keep last item":
Only if the items' data structure is complicated, differences between items are isolated and many items are exactly the same, HOF may be slightly slower than recursive: