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