Is there a symbol or well-known idiom for the conditional function, in any of the APL dialects?
I'm sure I'm missing something, because it's such a basic language element. In other languages it's called conditional operator, but I will avoid that term here, because an APL operator is something else entirely.
For example C and friends have x ? T : F
LISPs have (if x T F)
Python has T if x else F
and so on.
I know modern APLs have :If
and friends, but they are imperative statements to control program flow: they don't return a value, cannot be used inside an expression and certainly cannot be applied to arrays of booleans. They have a different purpose altogether, which is just fine by me.
The only decent expression I could come up with to do a functional selection is (F T)[⎕IO+x]
, which doesn't look particularly shorthand or readable to me, although it gets the job done, even on arrays:
('no' 'yes')[⎕IO+(⍳5)∘.>(⍳5)]
no no no no no
yes no no no no
yes yes no no no
yes yes yes no no
yes yes yes yes no
I tried to come up with a similar expression using squad ⌷
, but failed miserably on arrays of booleans. Even if I could, it would still have to embed ⎕IO
or an hardcoded 1, which is even worse as far as readability is concerned.
Before I go ahead and define my own if
and use it on every program I will ever write, is there any canon on this? Am I missing an obvious function or operator?
(Are there any APL programmers on SO? :-)
Yes, there are APL programmers on SO (but not many!).
I think the answer is that there is no standard on this.
For a scalar solution, I use "pick":
x⊃f t
While for a Boolean array I use indexing as you do above:
f t[x]
I always use index origin zero, so there is no need to add 1, and the parens are not needed.
If these are not simple enough, I think you have to cover them with a function named "if". That will also let you put the true and false in the perhaps more natural ordering of t f.
An old, old idiom which did something like C's ternary operator ? :
and returned a result was the following:
r←⍎(¯3 3)[x=42]↑'6×8 ⋄ 6×7'
Note that this is written for origin 0 and the parens around the -3 3 are there for clarity.
x=42 evaluates to zero or one, depending on this answer we choose -3 or 3, and thus select and execute either the first 3 elements ("6x8") or last 3 elements ("6x7") of the string. The diamond ⋄ is just there for decoration.
Needless to say, one would probably not code this way if one had :if :else avaiable, though the control structure form would not return a result.
In Dyalog APL you can use:
'value if true' (⊣⍣condition) 'value if false'
The idea is applying ⊣
(left tack – which always returns its left argument, while discarding the right argument) either 0 (for false) or 1 (for true) times – to the right argument. So, if it is applied 0 time (i.e. not at all), the right argument is returned unmodified, but if it is applied (once), then the left argument is applied. E.g.:
a b←3 5
Conditional←⊣⍣(a=b)
'match' Conditional 'different'
different
a b←4 4
Conditional←⊣⍣(a=b)
'match' Conditional 'different'
match
or
Cond←{⍺(⊣⍣⍺⍺)⍵}
bool←a=b
'match'(bool Cond)'different'
match
The trouble with these:
(f t)[x]
x⌷f t
x⊃f t
is that both t
and f
get evaluated.
If you want to short-circuit the thing, you can use guards:
{x:t ⋄ f}
This is equivalent to
if (x) {
return t;
}
f;
in a C-like language.
This is a common question, I think the reason there is no standard answer to it is that for the things you do with APL, there is actually less need for it than other languages.
That said, it is sometimes needed, and the way I implement an IFELSE
operator in GNU APL is using this function:
∇Z ← arg (truefn IFELSE falsefn) condition ;v
v←⍬
→(0=⎕NC 'arg')/noarg
v←arg
noarg:
→condition/istrue
Z←falsefn v
→end
istrue:
Z←truefn v
end:
∇
The function can be called like this:
3 {'expression is true' ⍵} IFELSE {'was false' ⍵} 0
was false 3
This particular implementation passes in the left-hand argument as ⍵
to the clause, because that can be handy sometimes. Without a left-hand argument it passes in ⍬
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With