10

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? :-)

Tobia
  • 17,856
  • 6
  • 74
  • 93

6 Answers6

15

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.

ngn
  • 7,763
  • 6
  • 26
  • 35
  • er silly question. is a one liner required? (yes I know this is APL), but if you want to avoid executing both functions whats wrong with a simple conditional execution. (sorry i dont have APL keyboard), something like:... execute (some_boolean) / 'f' execute (~some_boolean)/'t' clarity is not a sin! – RFlack Oct 08 '15 at 18:56
  • @ngn so, after fixing my vim-apl bug, I was trying to get something like this... only to find out it's Dyalog-only! argh, too bad. – Ven Nov 02 '15 at 21:21
  • Yes, execute could be used for this purpose, but I prefer to avoid execute unless it is clearly the best way to solve an issue. In this case, creating a small utility fn that takes the two expressions as input and uses a control structure to evaluate only the appropriate argument will work and IMO be clearer. Such a fn can return a result. – David Siegel Oct 10 '16 at 17:55
11

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.

Paul Mansour
  • 1,436
  • 9
  • 11
  • Thank you. I come from a C background, so index origin at zero makes a lot of sense to me, but I didn't want to go against the "APL way" – Tobia Apr 02 '13 at 21:47
  • 1
    Tons of Iverson's papers assume origin zero throughout. It's a valid choice if it simplifies what you're doing. – luser droog Jul 16 '16 at 05:04
  • 1
    I'm new to APL, so I could be misunderstanding, but I think the need for parenthesis in the second expression might depend on the dialect. In the book "Mastering Dyalog APL" by Bernard Legrand available on Dyalog's website (https://www.dyalog.com/uploads/documents/MasteringDyalogAPL.pdf) on page 172 it says that IBM compatible versions of APL handle this differently than Dyalog does. – j_v_wow_d Feb 21 '22 at 01:16
  • @j_v_wow_d Yes, that's correct. APL2 and similar dialects do require parenthesis with bracket indexing. – Adám May 17 '22 at 04:00
  • And that list includes GNU APL, in which `f t[x]` is a `RANK ERROR`. `(f t)[x]` works cross-dialectically. – Mark Reed Mar 22 '23 at 17:44
7

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
Adám
  • 6,573
  • 20
  • 37
6

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.

Lobachevsky
  • 1,222
  • 9
  • 17
  • Isnt that a bit messy? ( I hate having to count lengths of char vectors!). I dont have APL keyboard here but could one not use a nested array of two char vectors as the rarg of take? I suspect the answer to the OP depends on the context which wasnt totally clear to me. – RFlack Oct 01 '15 at 17:43
  • 1
    The last time I saw or used this was around 1979 on one or another (Sharp or STSC) timesharing system. Nested arrays were not available at the time. – Lobachevsky Oct 08 '15 at 13:46
1

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 .

Elias Mårtenson
  • 3,820
  • 23
  • 32
0

The APL expression:

(1+x=0)⌷y z 

should be the C language equivalent for

x?y:z

And all the others

(1+x>0)⌷y z 

for

x<=0?y:z

Etc. In general if a b c are expressions of respective languages the APL expression:

(1+~a)⌷b c

It should be equivalent to the C language:

a?b:c
RosLuP
  • 153
  • 7