Tricks for dealing with /
and ⌿
in trains
When using trains you may want to use reductions f/
like sum +/
or even replicate reduction //
. However, if your train has more parts to the left of the reduction you need parentheses to create an atop. Here are some tricks to save bytes.
Use 1∊
instead of monadic ∨/
or ∨⌿
on Boolean arrays
Task: Given two equal-length strings A and B, return 2 if any corresponding characters of A and B are equal, 0 otherwise. E.g. A←'abc'
and B←'def'
gives 0
and A←'abc'
and B←'dec'
gives 2
.
A dfn solution may be A{2×∨/⍺=⍵}B
but you want to shorten it by going tacit. A(2×∨/=)B
is not going to work because the rules of train formation parse this as 2 (× ∨/ =)
but you want 2 × (∨/=)
.
Observe that ∨/
or ∨⌿
on a Boolean vector (∨/,
or ∨⌿,
for higher rank arrays) asks whether there is any 1 present, i.e. 1∊
, so we can write our train as 2×1∊=
.
Note that ∊
ravels its right argument, so you cannot use it to reduce each row or column separately.
Use 1⊥
instead of monadic +/
or +⌿
Task: Given a list of lists L and an index N, return thrice the sum of the Nth list. E.g. L←(3 1 4)(2 7)
and N←1
gives 24
.
A dfn solution may be N{3×+/⍺⊃⍵}L
but you want to shorten it by going tacit. N(3×+/⊃)L
is not going to work because the rules of train formation parse this as 3(× +/ ⊃)
but you want 3 × (+/⊃)
.
Observe that evaluating a list of numbers in unary (base-1) is equivalent to summing the list because ∑{a, b, c, d} = a + b + c + d = (a × 1³) + (b × 1²) + (c × 1¹) + (d × 1⁰). Therefore +/a b c d
is the same as 1⊥a b c d
, and we can write our train as 3×1⊥⊃
.
Note that on higher-rank arguments, 1⊥
is equivalent to +⌿
.
Use f.g
instead of f/g
with scalar and/or vector arguments
Task: Given a list L and a number N, return the range 1 thorough the number of minimum division remainder when the elements of L are divided by N. E.g. L←31 41 59
and N←7
gives 1 2 3
.
A dfn solution may be N{⍳⌊/⍺|⍵}L
but you want to shorten it by going tacit. N(⍳⌊/|)L
is not going to work because the rules of train formation parse this as ⍳ (⌊/) |
but you want ⍳ (⌊/|)
.
The inner product A f.g B
of scalar two functions when the arguments are scalars and/or vectors is the same as f/ A g B
because both are (A[1] g B[1]) f (A[2] g B[2]) f (A[3] g B[3])
etc., so we can write our train as ⍳⌊.|
.
Note that this does not work for higher-rank arrays.
Use ∊⊆
instead of /
with Boolean left and simple vector right arguments
Task: Given a list L and a number N, filter the list so that only numbers greater than N remain. E.g. L←3 1 4
and N←1
gives 3 4
.
A dfn solution may be N{(⍺<⍵)/⍵}L
but you want to shorten it by going tacit. N(</⊢)L
is not going to work because the binding rules will parse this as (</) ⊢
but you want /
to be the function replicate rather than the operator reduce.
Dyadic ⊆
with a Boolean left argument partitions the right argument according to runs of 1s in the left argument, dropping elements indicated by 0s. This is almost what we want, save for the unwanted partitioning. However, we can get rid of the partitioning by applying monadic ∊
. Thus {(⍺<⍵)/⍵}
can become {∊(⍺<⍵)⊆⍵}
and thus we can write our train as ∊<⊆⊢
.
Note that this does not work for higher-rank arrays.
Use ∊⍴¨
instead of /
with non-Boolean left and simple vector right arguments
Task: Given a list L, replicate Nth item N times. E.g. L←3 1 4
gives 3 1 1 4 4 4
.
A dfn solution may be {(⍳⍵)/⍵}L
but you want to shorten it by going tacit. (⍳/⊢)L
is not going to work because the binding rules will parse this as (⍳/) ⊢
but you want /
to be the function replicate rather than the operator reduce.
Dyadic ⍴
combined with ¨
copies each element of the right argument according to the matching element in the left argument. This is almost what we want (e.g. 1 2 3⍴¨3 1 4 → (3)(1 1)(4 4 4)
). Then, we can get rid of the nesting by applying monadic ∊
. Thus {(⍳⍵)/⍵}
can become {∊(⍳⍵)⍴¨⍵}
and thus we can write our train as ∊⍳⍴¨⊢
.
Note that this does not work for higher-rank arrays.
Use 0⊥
instead of ⊢/
or ⊢⌿
with numeric arguments
Task: Given a list L and a number N, multiply the N with the rightmost element of L. E.g. L←3 1 4
and N←2
gives 8
.
A dfn solution may be N{⍺×⊢/⍵}L
but you want to shorten it by going tacit. N(⊣×⊢/⊢)L
is not going to work because the rules of train formation parse this as ⊣ (× ⊢/ ⊢)
but you want ⊣ × (⊢/⊢)
.
Observe that 0⊥
on a numeric array is the same as ⊢⌿
, so we can write our train as ⊣×0⊥⊢
.
Note that this selects the last major cell of higher-rank arrays.
1There is GNU APL. – M. Alaggan – 2015-01-03T13:11:03.157
@M.Alaggan: GNU APL is not very good though, especially for golfing. (It lacks proper d-fns, for one, and it certainly doesn't do trains or other fancy stuff.) If you want an open-source APL for golfing, ngn/apl is probably better. (Though that one's arguably a worse APL, as that one lacks the ∇-functions completely, but you don't use those for golfing anyway.) – marinus – 2015-01-04T14:00:48.167
@marinus Should it not be possible to contribute improvements to GNU APL so it kicks the same amount of arse? I have the program installed on Mac OS, how much is it lacking in terms of the language's coverage...? – None – 2015-09-15T04:04:45.937
+1 Excellent post. Regarding 4.3.
⊢
is better than⍨
for separating arguments, as it works on dyadic functions too, and doesn't cause syntax errors if the function is strictly monadic. – Adám – 2016-02-19T16:23:23.533Is there a way to get a free license beside having the raspberry pi version? – Fabinout – 2014-01-27T17:39:36.700
A legal way to get it, obviously. – Fabinout – 2014-01-27T18:01:55.230
3@Fabinout: At dyalog.com you can download a free Windows version. Click "Download Zone" and then "Unregistered Download". It will nag you to register but otherwise it's fully functional and free and legal. If you're a student, you can get the normal version for free by filling out a form. If you don't live in a country where they ruin your life for pirating, well, you know what to do. – marinus – 2014-01-27T18:06:59.843
There is also Nars2000, an open source implementation that has many more features than Dyalog (and some bugs.) Some of its features come in handy for golfing, such as the prime number functions or multisets. – Tobia – 2014-03-02T10:58:45.933