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'⍺':⍺ ⍺⍺ ⍵ ⋄ ⍺⍺ ⍵}
∇