Hi Robert,

I have quite a few thoughts when in comes to lambdas, in particular named lambdas and multi-line lambdas. The limitations that you see are primarily caused by concerns that otherwise APL would develop into a non-APL direction. A language does not necessarily get better as the number of its features grows (see PL/I or Ada).

∘ lambdas are only elegant if they are short and obvious. Beast like *Perm* below are IMHO neither elegant nor readable. Brevity alone does not imply elegance, in particular not if overdone.

∘ named lambdas are contradictions in themselves. Also. recursion and nameless functions do not play well together because the recursion has to refer to itself in some way.

 ∘ The semantics of lambdas (as defined by Dyalog, chapter 8 of the Dyalog book) is not consistent with the rest of APL. For example (I will use ◊ to indicate end of line to kept things short):

*Z←1 ◊ Z←2 ◊ Z←3     ⍝ sets Z to 3.
*

In Dyalog multi-line lambdas (using *λ←* to indicate the result):

*λ←1 ◊ ***λ*←2 ◊ ***λ*←3     ⍝ sets ***λ* to 1 and returns (!).
*

Also, local variables are handled differently than proper ∇-defined functions.

In contrast, GNU APL lambdas declare local variables in the same fashion as in proper ∇-functions:

*      ⊣{ E←(D+1),⍪D←1 2 3;D }**
**      )VARS**
**E**
*

All in all I would argue that having the same execution semantics for lambdas and for their proper ∇-function companions is far better than not. Implementation-wise  it is not too difficult to provide multi-line lambdas, but the implementation options to choose from are then: to adopt a bad solution as to maintain compatibility with Dyalog, or else to do it properly but become incompatible with Dyalog. Due to these complications I decided to drop multi-line lambdas entirely.

∘ What exactly is the advantage of a multi-line lambda compared to a proper ∇-function? Is A←{...} that much better than ∇A ... ∇ ? I rather doubt so.

∘ Gnu actually has a built-in If/Else constructor (i.e. ⊢ with axis):

*    'foo' ⊢[0] 'bar'**
**foo**
**      'foo' ⊢[1] 'bar'**
**bar*

The *i**f/else* condition *X* is the axis and the alternatives are the left and right arguments of*A ⊢[X] B*.

If I compare the alternatives:

*{ 'foo' ⊢[⍵] 'bar' }
{ :If ⍵ ◊ 'foo' ◊ :Else ◊ 'bar' ◊ :Endif }   ⍝ ◊ shall mean CR/LF*

thenn the first one convinces me more. Also, the second seems to work only in proper ∇-functions but not in Dyalog lambdas (at least I could not figure how in tryapl.org).

∘ lexical scoping: If I understand this term correctly then it means that local variables of a function are not visible in sub-functions called by it. From an APL point of view I consider that a limitation rather than an advantage. In APL it is the called function that decides which variables are local (and thus hide the non-local ones) while in lexical scoping it is the calling function that hides them. One can argue which one is better, but having both is IMHO the worst solution. As a C/C++ programmer I am used to lexical scoping by default, but I never missed it in APL.

There is another GNU APL feature, dyadic → (aka. relative jumps similar to monadic *→N+↑⎕LC*), that need no labels and therefore not only works in defined functions but also in immediate execution mode. I am not advertising it much because I believe that all APL extensions will sooner or later fire back (lambdas being one example). In *A → B* is B the branch condition and A the offset from the current line (negative to branch backwards.


Best Regards,
Jürgen



On 4/3/23 20:12, Robin Haberkorn wrote:
Hello everybody,

I stumbled across an interesting little problem. I would like to generate all possible combinations of taking ⍺ things from a total of ⍵. The number of possible combinations is consequently ⍺!⍵.

Here's a straight-forward "brute force" solution:

Perm ← {(X/⍨⍺=+/¨X←(⊂2⍴⍨⍵)⊤¨⍳2*⍵) /¨ ⊂⍳⍵; X}

      2 Perm 4
 3 4  2 4  2 3  1 4  1 3  1 2
      3 Perm 4
 2 3 4  1 3 4  1 2 4  1 2 3

Unfortunately the algorithm has O(2^⍵) time and space complexity. Which is okay for what I am using it, but I was still curious of how this could be solved recursively in a lambda. I feel that simple things like this should have elegant solutions in GNU APL. Unfortunately this is the best I could come up with:

Perm ← {⍎∊('↑,/X,¨¨X+(⍺-1) Perm¨⍵-X' 'X')[1+⍺≤1] ⊣ X←⍳1+⍵-⍺; X}

At this point I was really feeling the limitations of lambdas in GNU APL. There apparently aren't enough means of control flow. At least I couldn't find a way to utilize one of APL's operators elegantly for this purpose, so I fell back to a computed ⍎, which feels really clumsy and is probably quite slow as well.

Or you write a traditional ∇ function with →... I mean you could also write your own ⍶IfElse⍹ operator, but due to the lack of lexical scoping this would be pretty useless for recursion, unless you pass in your context as ⍺ or ⍵ which is again very clumsy.

I would therefore claim that we are either lacking lexical scoping and/or built-in structured If-Else constructs. Or lambdas should simply be allowed to contain ⋄, new lines and →. Or I am missing something obvious. I am not sure. But IMHO something fundamental is missing in the language.

I am interested in hearing your thoughts.

Yours sincerely,
Robin

PS: I am not saying "I want it like in Dyalog!!!11". GNU APL is great for what it is and I am not ready to switch over to Dyalog yet. I particularly like two things about GNU APL: 1) It's FREE software. 2.) It's more conservatively designed than Dyalog.

Reply via email to