Ops
One reason why iogii really is simple is that most ops are completely trivial and don't have any special cases. You can know everything there is to know just by looking at their name, type, and example. This is a catalog of all ops that aren't already completely obvious from their quickref description.
Reshape
Take n elements from a list, then recurse on that many elements dropped. n will typically be the same number and hence the second arg is repeated instead of promoted so that you can provide a list instead (see Nitty Gritty:special reptitions).
Typical usage:
"abcdef" 2 reshape → ["ab","cd","ef"]
But you can take different numbers of elements at each step:
"abcdef" 1,2,3 reshape → ["a","bc","def"]
You can even take 0 elements (negative is treated as 0 also).
"abcdef" 3,0,3 reshape → ["abc","","def"]
If it ever tries to take more than there is, then it will terminate, returning what it found so far.
"abcdef" 4 reshape → ["abcd","ef"]
Trailing 0s will work if it didn't try to previously take more than there was:
"abcdef" 6,0,0,1 reshape → ["abcdef","",""]
If the second arg ends then the results end too:
"abcdef" 2,2 reshape → ["ab","cd"]
I was inspired by the mold sort challenge to make sure that trailing 0s work. This somewhat felt like cheating, but really this is the most intuitive behavior for the op. It takes hands on experience to truly understand how to make ops as general as possible, and I'm sure I haven't perfected every op. If you ever wish an op was a bit different and think it is an overall improvement you can cheat too! Let me know!
Transpose
You can transpose a list of different length lists, it will fill in missing values with the default value for that type:
"abcd","ef","1234" transpose → ["ae1","bf2","c 3","d 4"]
But it will truncate instead if there are no more values after a point:
"abc","1" transpose → ["a1","b","c"]
Or
or
should be very intuitive, but it is worth mentioning that it is handled specially so that it doesn't coerce an int
to a str
for the first arg. Doing so would always be truthy since the string would also be nonempty.
4 "a" Or → "4"
0 "a" Or → "a"
Note the need for capitalizations since the result is a string (rank 1). Lowercase would coerce to a string then do an or
for each char value which will always be truthy still.
0 "abc" or → "0"
Index / Get
get
returns the ith element (0 indexed) or the default value for the type if out of bounds. Special behavior for negatives or out of bounds is likely less useful since it can be simulated using reverse
or repeat concat
.
index
finds the first index of an element in a list but is 1 indexed. This is so that the result can be falsey (0) if not found.
SetDiff
setDiff
removes the elements of the second arg from the first. If there are two occurrences of an element it will remove up to two of that element from the first, and so on for higher counts.
ChunkWhen
This op is likely to be rarely used, but very useful when it is, and it is the only op that can allow you to split a list up by an arbitrary criteria. (Besides doing it manually which seems difficult). I have gone through several variations of this op over the years and settled on the current behavior as the most versatile and easy to use. You can accomplish things like grouping truthy elements together (removing falsey) and grouping adjacent equal elements very easily with this op.
It splits the first list after each falsey value from the second list.
"abcd" 1,0,1,1 chunkWhen → ["ab","cd"]
Because the value corresponding to 'b
is 0, it split after that value.
Note that the last 1
isn't actually needed since the first list is over before the next split would be relevant.
"abcd" 1,0,1 chunkWhen → ["ab","cd"]
But if the last value had instead been a 0, that would indicate the next list has started, so the behavior would be different:
"abcd" 1,0,1,0 chunkWhen → ["ab","cd",""]
But if we remove another number then we terminate the list.
"abcd" 1,0 chunkWhen → ["ab","c"]
Extra condition values are also ignored.
"ab" 1,1,1,1 chunkWhen → ["ab"]
"ab" 0,0,0,0 chunkWhen → ["a","b",""]
And as promised, here is how we could group truthy values (if you wanted to define what truhty is just do something other than mdup ;
):
"ab bc"; '- cons chunkWhen tail → ["ab","bc"]
The cons value is ignored but necessary to align things correctly, this would be more elegant if there were a cons0
op.
This will return empty lists if multiple falsey values are present in a row (just filter if you don't want those).
And how we could group adjacent equal elements (similarly you could also define equality differently by doing something other than dup :
):
"aabbcdee" ::tail= chunkWhen → ["aa","bb","c","d","ee"]
"abbcde" ::tail= chunkWhen → ["a","bb","c","d","e"]
charClass
This op checks if a char is in any of the char classes:
- Lowercase letters
- Uppercase letters
- Digits
- Symbols
- Space / newline
(You can you use the acronym LUDS, shown in quickref, to remember the order, you are unlikely to use the final space / newline).
The second arg is converted to binary and those digits tell whether to include each char class or not. So for example the char class 5
is 1,0,1
which means lowercase or digit.
"aB4. " 5 charClass → [1,0,1,0,0]
Read / ReadAll
These ops ignore all non numbers and leading negative signs to return parsed numbers from a string. read
is just the head
of readAll
.
read
will return 0 if no numbers are present, if you wanted to detect that you could check the length of readAll
.