Returning functions from functions: TRADFNS vs DFNS

General APL language issues
Post Reply
petermsiegel
Posts: 159
Joined: Thu Nov 11, 2010 11:04 pm

Returning functions from functions: TRADFNS vs DFNS

Post by petermsiegel »

Tradfns allow you to return functions, but dfns don't. What's the history and reasoning for this distinction?

Code: Select all

      ⎕FX 'R←TESTT N' ':IF N=1 ⋄ R←+ ⋄ :ELSE ⋄ R←- ⋄ :ENDIF'
      2 (TESTT 1)3
5
      2 (TESTT 0)3
¯1
      TESTD←{ ⍵=1: + ⋄ -}  ⍝ Or try _←+ etc..
      2 (TESTD 1)3
SYNTAX ERROR
TESTD[0] TESTD←{⍵=1:+ ⋄ -}
                    ∧
Apologies if this is discussed somewhere on the Forum or in the documentation. This can be quite a useful feature! [P.S. This is a contrived, simple example. Its usefulness is in more complex cases.]

See also the APL Wiki: https://aplwiki.com/wiki/Defined_function_(traditional)
User avatar
StefanoLanzavecchia
Posts: 113
Joined: Fri Oct 03, 2008 9:37 am

Re: Returning functions from functions: TRADFNS vs DFNS

Post by StefanoLanzavecchia »

If you could get your hands on John Scholes' wonderful presentation at Dyalog'11 (https://en.wikipedia.org/wiki/John_M._S ... les2011-66) you would probably find a lot of answers. Unfortunately, it does not seem to be on YouTube. I was there at the Dyalog User Group Meeting in 2011 and I remember bits of it. At the time John also distributed an experimental version of the interpreter in which dfns could return functions in addition to arrays. So, if you could get your hands on the presentation I am sure you would find it very interesting. How to go about it, though, I don't know...
petermsiegel
Posts: 159
Joined: Thu Nov 11, 2010 11:04 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Post by petermsiegel »

Thanks for sharing that. I remember that interpreter. I'm not sure, but that one (or another one?) had closures (bundling persistent state with returned functions) as well, which were/are very useful.

thanks again.
Veli-Matti
Posts: 94
Joined: Sat Nov 28, 2009 3:12 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Post by Veli-Matti »

There's this clumsy way how to simulate function setting:
SetSort←{Sort∘←⍋ ⋄ 1=⍵:⍵ ⋄ Sort∘←⍒ ⋄ ⍵}
It's better than nothing.

-Veli-Matti
petermsiegel
Posts: 159
Joined: Thu Nov 11, 2010 11:04 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Post by petermsiegel »

Thank you for the suggestions.

The workaround I selected was to enclose the workhorse dfn inside a tradfn that (given the right option) returns a dfn as a result. It works fine, but it is a kludge nonetheless.
User avatar
Adam|Dyalog
Posts: 143
Joined: Thu Jun 25, 2015 1:13 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Post by Adam|Dyalog »

While dfns don't come with closures out of the box, you can easily make them yourself:
closure←⎕NS⍬
      closure.asc←1
      Sort←closure.{⍬≡⍴⍵:asc⊢←⍵ ⋄ asc:⍋⍵ ⋄ ⍒⍵}
      ⎕EX'closure'
Since a scalar cannot be sorted, we use the scalar argument to set state:
'hello'[Sort 'hello']
ehllo
      Sort 0
      'hello'[Sort 'hello']
ollhe
      Sort 1
      'hello'[Sort 'hello']
ehllo
We created the namespace separately and have remove it afterwards. At the cost of readability, we can inline its definition:
Sort←({⍵⊣⍵.asc←1}⎕NS⍬).{⍬≡⍴⍵:asc⊢←⍵ ⋄ asc:⍋⍵ ⋄ ⍒⍵}
Once we get array notation, this becomes much neater:
Sort←(asc:1).{⍬≡⍴⍵:asc⊢←⍵ ⋄ asc:⍋⍵ ⋄ ⍒⍵}
But right, dfns are not allowed to return functions (or operators). The ability of tradfns to do so was probably never planned, but just fell out of the implementations, and while not a documented feature, it isn't going away. It can therefore be used to preserve the source of tacit functions which would otherwise be lost or mangled immediately at definition time:
∇ F←Avg
        F←+⌿÷1⌈≢
      ∇
However, this doesn't work for the closure, as it'd re-create the namespace upon every invocation. Instead, we can define a tradfn which replaces itself with, and returns, the actual function. This function can safely be stored in a text source file:
∇ F←Sort
        ⎕EX'Sort'
        F←Sort←({⍵⊣⍵.dir←1}⎕NS ⍬).{⍬≡⍴⍵:dir⊢←⍵ ⋄ dir:⍋⍵ ⋄ ⍒⍵}
      ∇
petermsiegel wrote:enclose the workhorse dfn inside a tradfn that (given the right option) returns a dfn as a result.
No need to defer the choice of which function to return to the tradfn; we can let the workhorse dfn return an Object Representation and only let the container tradfn return it bound as operand to an operator which will apply the function at call time, since Object Representations become functions when used as operands:
∇ F←TEST N;or
        or←{f←+ ⋄ g←- ⋄ ⍵:⎕OR'f' ⋄ ⎕OR'g'}N
        F←or{2=⎕NC'⍺':⍺ ⍺⍺ ⍵ ⋄ ⍺⍺ ⍵}
      ∇
petermsiegel
Posts: 159
Joined: Thu Nov 11, 2010 11:04 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Post by petermsiegel »

Very clever (and workable) solution, especially the Object Representation snippet. Thank you.
Post Reply