Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional function in APL

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

like image 509
Tobia Avatar asked Apr 01 '13 22:04

Tobia


5 Answers

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.

like image 114
Paul Mansour Avatar answered Nov 06 '22 04:11

Paul Mansour


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.

like image 35
Lobachevsky Avatar answered Nov 06 '22 02:11

Lobachevsky


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
like image 45
Adám Avatar answered Nov 06 '22 04:11

Adám


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.

like image 15
ngn Avatar answered Nov 06 '22 03:11

ngn


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 .

like image 1
Elias Mårtenson Avatar answered Nov 06 '22 03:11

Elias Mårtenson