If we let {...} be a code block (distinguished from a d-function by not having top-level ⍵), we can have sequences like:
Code: Select all
i← 0 ⋄ j←1
nextI←{i+←1 ⋄ i}
nextJ2←{j×←2 ⋄ j}
The basic idea is that the code block would only be executed when required-- that is whenever its values are required, e.g. during a numerical operation
Code: Select all
a←nextI÷nextJ2 ⍝ 1÷2, 2÷4, ...
or when peeking:
Code: Select all
⍴,{ ⎕←nextI ÷ nextJ2}
.3875
1 ⍝ it has one item
This also allows a convention for lazy evaluation of boolean expressions, without fundamentally changing boolean definitions. E.g. b1 ∨ b2 can be defined as evaluating b2 and if true, leaving b1 unevaluated:
Code: Select all
:if {i ≤ 10} ∨ { flagTrue} ⍝ i≤10 not evaluated if flagTrue.
Lazy evaluation could delay evaluation for any general structural operations that do not peer inside the block:
Code: Select all
5 + {⍳5} ⍝ immediately evaluated to 6...10
i234←{⎕←'i234 run' ⋄ ⍳2} {⍳3} {⍳4}
⍴i234 ⍝ does not peer inside, since there are 3 blocks, each of which is a scalar "envelope"
3
⍴¨i234 ⍝ has to peer inside, so lazy code blocks are evaluated in situ
i234 run
2 3 4
Any operation that requires knowledge of internal structure or contents will force evaluation; this includes: depth ≡ catenate , and so on, to keep code blocks otherwise equivalent to their evaluated brethren:
Code: Select all
first last ← 'John' 'Jones'
name ← {first,' ',last}
'My name is ',name
My name is John Jones
last ← 'Smith'
'His name is ',name
His name is John Smith
{1, 3, 5}, {two ← 2 ⋄ 6 7 + ⍳two}, 11 ⍝ Catenation forces execution
1 3 5 7 9 11
We can force evaluation by a definition of monadic ⊢ to indicate it will evaluate its argument, without changing its shape...
Code: Select all
⊢ {first, ' ', last}
John Smith
Given this definition, code blocks can be passed to functions and can form the basis of if-then assignments. We can imagine a ⎕THEN function (choose an appropriate native symbol):
Code: Select all
benefits ← (total ≤ 100000) ⎕THEN { total × 1.1025} {total x 1.01} ⍝ Choose the first block (1.1025) if the condition (total ≤ 100000) is true, else the second block...
Or even:
Code: Select all
benefits ← (1++/total > 100000 200000 ) ⎕SELECT { total × 1.053} { total × 1.1025} {total x 1.01} ⍝ Select the first block if total ≤100000, second if ≤200000, else 3rd
Note that this is the same as
Code: Select all
benefits ← ( 1++/total > 100000 200000 ) ⊃ { total × 1.053} { total × 1.1025} {total x 1.01} ⍝ Logical selections could be developed without a lot of extra syntactic sugar...
Because this approach fits in well with existing d-function syntax (having some superficial similarities to a 0-adic dfn), it should be easy to learn and provides needed extensions to APL semantics, without proliferation of :IF :ANDIF :ORIF types of structures. While I didn't show any sophisticated examples of vector-intensive logic, it would be easy to show without additional rules.