Returning functions from functions: TRADFNS vs DFNS

General APL language issues

Returning functions from functions: TRADFNS vs DFNS

Postby petermsiegel on Thu Nov 24, 2022 10:54 pm

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)
petermsiegel
 
Posts: 140
Joined: Thu Nov 11, 2010 11:04 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Postby StefanoLanzavecchia on Fri Nov 25, 2022 8:10 am

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...
User avatar
StefanoLanzavecchia
 
Posts: 109
Joined: Fri Oct 03, 2008 9:37 am

Re: Returning functions from functions: TRADFNS vs DFNS

Postby petermsiegel on Fri Nov 25, 2022 4:39 pm

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.
petermsiegel
 
Posts: 140
Joined: Thu Nov 11, 2010 11:04 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Postby Veli-Matti on Sun Nov 27, 2022 11:34 am

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

It's better than nothing.

-Veli-Matti
Veli-Matti
 
Posts: 93
Joined: Sat Nov 28, 2009 3:12 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Postby petermsiegel on Mon Nov 28, 2022 6:20 am

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.
petermsiegel
 
Posts: 140
Joined: Thu Nov 11, 2010 11:04 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Postby Adam|Dyalog on Wed Nov 30, 2022 2:47 pm

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'⍺':⍺ ⍺⍺ ⍵ ⋄ ⍺⍺ ⍵}
User avatar
Adam|Dyalog
 
Posts: 134
Joined: Thu Jun 25, 2015 1:13 pm

Re: Returning functions from functions: TRADFNS vs DFNS

Postby petermsiegel on Wed Nov 30, 2022 10:16 pm

Very clever (and workable) solution, especially the Object Representation snippet. Thank you.
petermsiegel
 
Posts: 140
Joined: Thu Nov 11, 2010 11:04 pm


Return to Language

Who is online

Users browsing this forum: No registered users and 1 guest