rslt ← (if ##.cond then cond else) arg     ⍝ proposition:consequence:alternative

Phil Last says: this operator implements the triadic structure:

    [if] proposition [then] consequence [else] alternative.

The  correct way to call it is as above, monadically with two calls to the oper-
ator  separating the three operands.  The resulting derived conditional function
is similar to the D: guard construct ...

    proposition : consequence ⋄ alternative

excepting  that it is a function, can be assigned a name, and within the D: con-
text its result is captured regardless of the truth of the proposition or not at
all.  Any  of the three, proposition, consequence and alternative, can be either
arrays  or  monadic (ambivalent) functions on arg. (proposition) or (proposition
arg)  must  be a boolean singleton. Any of them can of course be further (paren-
thesised) or named conditionals on arg.

The development started two decades ago in APL2 with defined operators such as:

        ┌──────────────────────┬────────────────────────────────┐
        │ ∇ r←(f then g)w      │ ∇ r←a(f else g)w               │
        │   r←↑g mon/(⍳f w),⊂w │   r←↑f mon/(⍳a),g mon/(⍳~a),⊂w │
        │ ∇                    │ ∇                              │
        └──────────────────────┴────────────────────────────────┘
where:
        ┌───────────────┐
        │ ∇ r←a(f mon)w │
        │   r←f w       │
        │ ∇             │
        └───────────────┘

    rslt ← (proposition then consequence) arg

    rslt ← test (consequence else alternative) arg

In  different  versions  of  both operators the control, here effected by use of
reduction  on  a  one   or two item vector, could instead be by branching, using
:If &c. control structures or latterly by use of a guard in a D:op. The idea was
to  make all of these methods redundant. The operators, (then) and (else), could
not  be  used together because the derived function (f then g else h) is dyadic,
as it is derived from (else), and will run either (f then g) or (h) according to
its  boolean  left argument where what is required is to run (f) unconditionally
followed by (g) or (h) according to its boolean result.

A  breakthrough was made on a napkin in Helsingør, a day or two earlier in truth
and  a  notebook,  by  coding  the two operators to work together to produce the
MONADIC  derived function (f then g else h) fulfilling these criteria. To do so,
arguments  were  passed from (else) to (then) to control the calling of the pro-
position  and consequence separately if at all. These worked exactly as expected
and  were  also  upwardly  compatible with the definitions above. Here are their
definitions ...

    ┌─────────────────────┬───────────────────────┐
    │ then←{⍺←'M'         │ else←{⍺←'M'           │
    │     ⍺='Q':(⊢∘⍺⍺)⍵   │     ⍺=1:(⊢∘⍺⍺)⍵       │
    │     ⍺='Y':(⊢∘⍵⍵)⍵   │     ⍺=0:(⊢∘⍵⍵)⍵       │
    │     (⊢∘⍺⍺)⍵:(⊢∘⍵⍵)⍵ │     'Q' ⍺⍺ ⍵:'Y' ⍺⍺ ⍵ │
    │     ⍵               │     (⊢∘⍵⍵)⍵           │
    │ }                   │ }                     │
    └─────────────────────┴───────────────────────┘

Notice the (almost) identical lines in each.

In  (else)  these operate the older standalone use where a boolean left argument
determines  whether  the consequence or the alternative should be run. In (then)
these carry out the instruction passed in the left argument by the third line of
(else)  to  run the proposition and possibly the consequence. The other lines of
(then)  operate  the  older  standalone monadic use. However rigorously defined,
having  two  disparate  operators which can both be used independently but which
CAN  work  in  concert  and  must  agree  on an arbitrary protocol to do so goes
against the spirit if not the letter of good functional programming.

Also,  a conditional without an alternative, (proposition then consequence), can
be  considered  in  the same dim light. Nevertheless they lasted a month before,
walking  around  Københavns  Søen, I realised this weakness could be overcome by
producing a single operator that implements the best of both without any depend-
encies.  In  fact  the  napkin coding of (else) as it stood was adequate for the
task after substituting 2, 1 and 0 for 'M', 'Q' and 'Y' but the clause ...

    rslt ← (proposition else consequence else alternative) arg

has  lost  its meaning and confuses more by the fact that it SEEMS to mean some-
thing while not actually doing so.

(
    This  may be the prejudice of a native English speaker; I have heard, though
    I  think  it's probably a misunderstanding, that some eastern languages lack
    words  for  the  concepts  carried by "therefore" and "because". I have also
    heard  that programmers in eastern countries prefer the APL language because
    it is not encumbered with English (or western) language contructs.
)

The  final  coding  of  the  operator  dispenses with the standalone use of both
(then) and (else). Thus it is always coded twice separating the three operands.

I  decided  that  using  the left argument as an "internal" flag really aught to
preclude  its  use otherwise so although it's not impossible to call the derived
function  dyadically its use is deprecated and its results are rather unpredict-
able.  Including the different permutations of array and function operands there
were sixteen calling sequences for the (then) and (else) operators used individ-
ually  and in combination. With the restrictions imposed by a single conditional
symbol only usable in combination we are left with eight ...

    RSLT ← (proposition cond consequence cond alternative) ARG
    RSLT ← (proposition cond consequence cond OTHER) ARG
    RSLT ← (proposition cond VALUE cond alternative) ARG
    RSLT ← (proposition cond VALUE cond OTHER) ARG
    RSLT ← (TEST cond consequence cond alternative) ARG
    RSLT ← (TEST cond consequence cond OTHER) ARG
    RSLT ← (TEST cond VALUE cond alternative) ARG
    RSLT ← (TEST cond VALUE cond OTHER) ARG

Some of the parentheses in the above are redundant. If you don't know which, you
are  best  to leave them in. The last clause makes no use of ARG except to force
APL to call the derived function rather than assigning it into RSLT!

An alternative coding
---------------------
An alternative, if slightly more challenging, coding of cond might be:

    cond←{ ⍝ proposition : consequence : alternative
        m q y←147036925 258147036 369258147
        ⍺←m
        ⊢∘⍺⍺⍣(⍺=q)⊢⊢∘⍵⍵⍣(⍺=y)⊢⍺⍺{(q ⍺⍺ ⍵)⍺⍺{y∘⍺⍺⍣⍺⊢⊢∘⍵⍵⍣(~⍺)⊢⍵}⍵⍵ ⍵}⍵⍵⍣(⍺=m)⊢⍵
    }

Examples:

    eis←1∘=∘≡cond⊂cond⊢         ⍝ enclose if depth=1.

    1 disp      1 (,1) (⊂,1)    ⍝ items have depth 0 1 2
┌→┬─┬───┐
│ │ │┌─┐│
│1│1││1││
│ │ │└→┘│
└─┴→┴───┘
    1 disp eis¨ 1 (,1) (⊂,1)    ⍝ enclose depth-1 items.
┌→┬───┬───┐
│ │┌─┐│┌─┐│
│1││1│││1││
│ │└→┘│└→┘│
└─┴───┴───┘

    unless←{~∘⍵⍵ cond ⍺⍺ cond⊢⍵}

    log←⍟unless(≤∘0)

    log 3
1.098612289

    log 0
0
    or←{(∨/⍺)cond((0⊥⍺)cond ⍵⍵ cond((2=⍴⍺)cond ⍺⍺ cond((¯1↓⍺)∘⍺⍺)))cond⊢⍵}

    0 0 0 0-or×or⌈or⌊7.5
7.5
    0 0 0 1-or×or⌈or⌊7.5
7
    0 0 1 0-or×or⌈or⌊7.5
8
    0 1 0 0-or×or⌈or⌊7.5
1
    1 0 0 0-or×or⌈or⌊7.5
¯7.5

    ⍝ Used as a dyadic, rather than "triadic" construct,
    ⍝ cond is equivalent to →else←:

    0 1 ÷cond-¨ 3
¯3 0.3333333333

    0 1 ÷else-¨ 3
¯3 0.3333333333

See also: while until else and or co_ops

Back to: contents

Back to: Workspaces