# Ops

One feature of iogii 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. Their power comes from combining them.

This is a catalog of all ops that aren't obvious from their quickref description.

FYI Many ops are named after their Haskell equivalent.

## 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 [Types:special reptitions](types.html#specialrepetitions)).

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](http://golf.shinh.org/p.rb?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"]

## 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`.

## 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.

## SortBy

It is stable and O(n log n).

## 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`.

## ToBase / FromBase

These ops convert to / from an arbitrary base. They return / expect the digits to be in most significant digits first. The `bits` op will return least significant digits first.

0 will become the empty list.

Note that because `fromBase` overloads `max`, the second arg to `X` cannot promote for a `max` operation, but `max` is commutative so you likely could just flip the arg order to do that.

Also keep in mind that `toBase` low rank overloads based on the first arg not the second (so you would need commas if vectorizing more than once for it).

## Digits / Undigits

These ops are more like converting a number to a string and then reading those digits than `toBase` / `fromBase` (most significant digits first). Hence the mnemonics: `U` concatenates the digits and `P` transposes digits.

## Join

If you join a string (instead of a list of strings), it promotes each character to a string (rather an unvectorized promote which would be useless here).

    "abc" " " * -> "a b c"

## A<sub>char</sub> Ops

Some ops are typically associated with string manipulation (e.g. `join`) but there is really nothing specific about them being strings needed for them to work. These ops have arg types `a`<sub>`char`</sub>. Which means they are defined for chars and equivalently to chars but can also be used generically - which means you can add commas to raise their rank or use them with integers.

For example `* join` can be used to intersperse integers into a list like so:

    1,2,3,,4,5,,6 10,11 *, -> [1,2,3,10,11,4,5,10,11,6]

This would work with promotions just like chars:

    1,2,3 4 *, -> [1,4,2,4,3]

You can also increase the rank these ops operate at (`,` for char and `,,` for int):

    "1","2","3" "4" *, -> ["1","4","2","4","3"]

As opposed to it used normally with:

    "1","2","3" "4" * -> "14243"

More commas can be used for even higher ranks.

Ops like `` strip` and `_ words` use the concept of whitespace which is just [truthiness](types.html#truthiness) in the general case:

    0,1,2,0,3,4,0,0 `, -> [1,2,0,3,4]

Ops like `/ rightJustify` use spaces, which is just the [default value](types.html#defaultvalue) for a type in the general case:

    10 3 /, -> [0,0,10]

The ops `/ rightJustify` and `/ split` would be ambiguous if used generically on ints so `split` on ints is `%,`. Similarly `replicate` on ints is `^,` (which would have been ambiguous with `* join`.

    1,2 3 ^, -> [1,2,1,2,1,2]

Substring based [slicing](#slicingops) can be used generically on higher rank chars but not ints (since that would be ambiguous with the index oriented version of the op).

    "a","b","c","b","d" "b" #, -> [["a"],["c"],["d"]]

## 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` is the op stops splitting when the second arg runs out and returns the remaining list of the first arg.

    "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",""]

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:

    "ab bc"; consDefault chunkWhen tail -> ["ab","bc"]

The `consDefault` is necessary to align things correctly (but the value is ignored by the later `tail`). If you wanted to provide custom truhty behavior, just modify the duplicated value after the `consDefault`.

This will return empty lists if multiple falsey values are present in a row (just filter if you don't want those).

And here's how we could group adjacent equal elements (similarly you could also define equality differently by doing something after the `dup :`):

    "aabbcdee" ::tail equal chunkWhen -> ["aa","bb","c","d","ee"]
    "abbcde" ::tail equal chunkWhen -> ["a","bb","c","d","e"]

## CharClass

`charClass` and `isCharClass` ops are not actually complicated, but they are a bit unusual so require some explanation.

`charClass` returns all the characters that are in the char class of each letter of the arg. So for example:

    "an4" charClass -> "abcdefghijklmnopqrstuvwxyz0123456789"

`a` and `n` are in the same char class (lower case alphabet letters), so only the first does anything, and `4` is present so all the digit characters are added.

The char classes are:

    abcdefghijklmnopqrstuvwxyz
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    0123456789
    !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
    newline space

The `isCharClass` op checks if any character is in any of these classes.

# Slicing Ops

If these ops are called with the second arg being `[char]` (or `char` which will promote to `[char]`), then that substring is searched for and used in place of an index.

So `d` is `dropUntilAfterSubstring` instead of `drop`, etc.

    "beatles" "at" d -> "les"

`g` would get the substring if it matched (empty string otherwise).

`#` repeatedly matches substrings, effectively performing a `splitKeepEmpties` aka `cut`.

Uppercase versions of these take in a list of possible substrings to match the first of.

    "beatles" "l","a" D -> "tles"

(because the `"a"` was found first).

`-` (`cutAny`) is just the uppercased version of `#`.

`+` (`scanAny`) is all the matches found in a `cutAny`.

This table is redundant based on the integer definitions of these ops and the info above, but it could be useful to understand or refer to the ops by name:

`# cut splitKeepEmpties` `[achar] {[achar]} => [[achar]]` `"a..b.c." "."# => ["a","","b","c",""]`

`d dropUntilAfterSubstring` `[achar] [achar] => [achar]` `"beatles" "at" d => "les"`

`k keepUntilSubstring` `[achar] [achar] => [achar]` `"beatles" "at" k => "be"`

`g getSubstring` `[achar] [achar] => [achar]` `"beatles" "at","z" g => ["at",""]`

`D dropUntilAfterAnySubstring` `[achar] [[achar]] => [achar]` `"beatles" "z","at" D => "les"`

`K keepUntilAnySubstring` `[achar] [[achar]] => [achar]` `"beatles" "z","at" K => "be"`

`G getAnySubstring` `[achar] [[achar]] => [achar]` `"beatles" "z","at" G => "at"`

See the [generic char ops](#asubcharsubops) section for why the type is `achar` instead of `char`.

## Iterate

`iterate` behaves like its Haskell counterpart. It is explained in the intro page's [circular programming](index.html#circularprogramming).

## Expand / Iterate0

Expand is an `iterate` from the default value (whose rank depends on the capitalization of `expand` and the return type of the function)

## Foldr

`foldr` is like `iterate` but starting from the right, and taking the first element as the final result. The [Circular Programming](circularprogramming.html) doc explains how it works.

## Meld / Foldr0

Meld is a `foldr` from the default value (whose rank depends on the capitalization of `meld` and the return type of the function)