defns ← {names←0 {list←0 {space←⎕this}}} ##.defs namelist ⍝ Extended ]defs.
[defs] implements an extended version of the ]defs user command. It takes a vec-
tor [namelist] as right argument and returns a display of the definitions to
which the names refer.
Left argument item [names] specifies whether names or values should be used for
derived function components
0: -names=off show values (default)
1: -names=fns show names of functions and operators where available
2: -names=all include names of arrays where available
succ ← (one←1)∘(plus←+) ⍝ definitions
0 defs 'succ' ⍝ showing component values
succ ← 1∘+
1 defs 'succ' ⍝ showing names of functions
succ ← 1∘plus
2 defs 'succ' ⍝ showing names of functions and arrays
succ ← one∘plus
[list] determines the listing order:
0: alphabetic listing (default)
1: -topdown top-down listing
¯1: -refs reference/dependency order (Hsu)
2 0 defs '' ⍝ alphabetical listing
one ← 1
plus ← +
succ ← one∘plus
2 1 defs 'succ' ⍝ top-down calling tree for "succ"
succ ← one∘plus
one ← 1
plus ← +
2 ¯1 defs 'one' ⍝ dependency (refs) tree for "one"
one ← 1
succ ← one∘plus
The final item of the left argument is the name[space] in which to find definit-
ions.
NB: The appearance of a name in the result indicates only that [defs] has found
a definition that matches the value of this component. If we withdraw the defin-
ition this will no longer be the case and the name will disappear from the disp-
lay:
mean ← (sum←+⌿)÷≢ ⍝ more definitions
1 defs 'mean' ⍝ "mean" with name for "sum"
mean ← sum÷≢
⎕ex'sum' ⍝ remove definition of "sum"
1 defs 'mean' ⍝ "sum" disappears from ]defs display
mean ← +⌿÷≢
Likewise, _changes_ to the definition of "sum" change the display of "mean" but
do not alter its behaviour.
sum ← +⌿ ⍝ reinstate definition of "sum"
1 defs 'mean' ⍝ display of "mean" incorporates the definition
mean ← sum÷≢
mean 1 2 3 4 ⍝ "mean" gives expected result
2.5
sum ← ? ⍝ change definition of "sum"
1 defs 'mean' ⍝ display of "mean" no longer references "sum"
mean ← +⌿÷≢
mean 1 2 3 4 ⍝ behaviour of "mean" is _unchanged_
2.5
Such considerations apart, defs can be helpful when developing derived functions
that reference other derived functions. For large "trees" of definitions, the
]boxing and ]defs value displays soon become unwieldy:
f ← + ⍝ tree of forks ...
g ← f f f
h ← g g g
i ← h h h
j ← i i i
]boxing -trains=def
Was -trains=def
j ⍝ boxing displays _values_
(((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++)(((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++)((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++
0 defs 'j' ⍝ display with values
j ← (((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++)(((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++)((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++
1 defs 'j' ⍝ display using names
j ← i i i
Remember that definitions can be corrected simply by changing and resubmitting
relevant lines of the ]defs display. For a demonstration of this technique, see
Sudoku-solver video: https://www.youtube.com/watch?v=DmT80OseAGs
2 defs '' ⍝ some definitions with names
fold ← ⌿
mean ← sum÷num
num ← ≢
one ← 1
plus ← +
pred ← -∘one
same ← succ∘pred
succ ← one∘plus
sum ← plus fold
Using the ¯1 option to display in referenced-by order makes it easier to main-
tain derived functions by resubmitting dependent definitions following a change
above them in the list.
2 ¯1 defs '' ⍝ all definitions in dependent order
fold ← ⌿
num ← ≢
one ← 1
plus ← +
pred ← -∘one
succ ← one∘plus
same ← succ∘pred
sum ← plus fold
mean ← sum÷num
After correcting one definition, "fold" say, in the above display, we must re-
submit dependent definition "sum" and definition "mean", which depends on that.
Because of the display order, the three definitions can be resubmitted in one
interaction. Remember that dependent definitions such as "sum" and "mean" above
must be reassigned, whether changed or not, in order to incorporate changes in
their dependents. To mark a definition for resubmission without changing it,
just add a blank to the end of the line.
1 ¯1 defs 'plus' 'one' ⍝ definitions dependent on "plus" and "one"
plus ← +
sum ← plus fold
mean ← sum÷num
one ← 1
pred ← -∘one
succ ← one∘plus
same ← succ∘pred
Finally, defs accepts an assignment expression, which automatically updates any
dependent definitions.
defs 'fold←/' ⍝ change defn and any of its dependents
Technical notes:
[defs]' primary data type "NKTDs" is a vector of [Name Kind Defn Tree]-tuples,
where:
Name: character vector. 'mean'
Kind: 2:array 3:function 4:operator. 3
Tree: vector of kinds of derived function components. (3 4)3 3
Defn: nested ⎕CR of the derived function. '+⌿' '÷' '≢'
Inner function [nabs] substitutes nested sub-expressions with names wherever
possible, using its own inner functions:
[names] takes a vector of kinds and returns an NKTDs vector for all names in
the target namespace. Definitions are reduced by substituting names for all
sub-expressions identical to those names' referent values. [names] applies
[subs] under reduction to the NKTDs vector, whose items have been sorted
into order of increasing size. This ensures that the largest possible subs-
titution is made at each step of the reduction. [names] is an O(×/d s*2)
function, where d is the number of definitions, and s the mean definition-
tree size.
(muse:
A common pattern in procedural programming is to update some variable X,
using function F, if predicate P is true:
X ← I
:If P
X ← F X
:EndIf
where X::T ("X is of type T"), F::T←∇T and P::Bool, for some type T.
The equivalent functional coding uses the power operator, which can bind
the predicate either at application time:
X ← F(⍣P)I
or, as in defs's inner function [names], at F-definition time:
F ← {...}⍣P
X ← F I
[defs] uses derived operators R and T for the conditional application of
a left operand function, depending on whether the listing option is for
refs (_l=¯1) or top-down (_l=1):
R←⍣(_l≡¯1) ⋄ T←⍣(_l≡1) ⍝ if -refs or if -topdown
R and T are used within inner function [tree]:
accm←{⍺,(⍺ new ⍵)/T⊂⍵} ⍝ collected lines and tab values
subs←{(⍺ new ⍵)/T⊃next/⍵} ⍝ unvisited edges
new←{~(⊃⍵)∊⊃¨⍺}T ⍝ node unvisited?
and for the conditional application of [dervs], a filter for those def-
initions that are derived functions:
trim↑⍵ tree dervs R defns ⍝ calling or called-by tree
) ¯¯¯¯¯¯¯
[subs] takes a vector of NKTDs processed so far as an accumulating left arg-
ument and the next definition to be examined on the right. Function →in← is
called to search the accumulated definitions for any occurrences of the new
definition and any _hits_ replaced with its name.
[uniq] removes duplicate definitions from the NKTDs vector, otherwise [defs]
would not be able to decide which name to substitute. For example, ⌊ in the
following definition of indx has two aliases "floor" and "min":
floor ← ⌊
min ← ⌊
indx ← ⊢⍳⌊/
defs'indx' ⍝ neither name substituted for ⌊
⊢⍳⌊/
)erase floor
defs'indx' ⍝ substitution occurs as ⌊ now has a unique name
⊢⍳min/
[nktds] returns an NKTDs vector for all one-line definitions in the target
namespace.
[prep] pre-processes nested (⎕CR) definitions by:
disclosing 1-vectors, which arise from named primitive functions, and
removing the "name←" tag from the start of any named dfns.
[ktree] takes a definition (nested ⎕CR) and attempts to return the equi-
valent nested vector of kinds. This involves a certain amount of guesswork
and is a weak component of the whole enterprise.
(muse: <V>
It is often difficult to deduce the kinds of derived function components
from their ⎕CR forms. The following distinct trains have identical ⎕CRs:
f←,,, ⋄ g←',',, ⋄ ⎕cr¨'fg'
┌───┬───┐
│,,,│,,,│
└───┴───┘
[defs] could be much improved by replacing [ktree] with an interpreter-
supplied mechanism (1∘⎕NC, say) to provide train-component kinds:
mean ← +⌿÷≢ ⋄ 1 ⎕NC 'mean' ⍝ kind-tree
┌───┬─┬─┐
│3 4│3│3│
└───┴─┴─┘
1 ⎕NC¨ 'fg' ⍝ (f g from above)
┌─────┬─────┐
│3 3 3│2 3 3│
└─────┴─────┘
)
[curry] adjusts the kind trees and definitions to accomodate right-operand
currying. This is where a dyadic operator binds its right operand to derive
a monadic operator. Dyalog allows us to name such derivations:
inv ← ⍣¯1 ⍝ derived monadic inverse operator
If such an operator is subsequently bound with a left operand:
enc ← ⊥ inv ⍝ derived function
the ⎕cr of the resulting function is a triple (⊥ ⍣ ¯1). In order for defs to
be able to substitute name "inv" for ⍣¯1, the representation of the function
is converted to the pairs: (⊥ ⍣ ¯1) → (⊥(⍣ ¯1)).
[expr] takes the reduced expression tree (D) together with its kind-tree (T),
and returns a parenthesised, linear form of the expression. [expr] traverses
(T D) pairs for each reduced definition, joining sub-expressions with appropri-
ate parentheses.
[crep] takes an array value and returns a character vector representing an expr-
ession that evaluates to that value. [crep] requires library utility function:
⎕SE.Dyalog.Utils.repObj.
[join] concatenates its argument expressions with a blank between adjacent names
or numbers.
[trim] removes outer blank columns from its character matrix argument.
[adj] returns a pair: the rightmost item of its left argument and the leftmost
item of its right argument: adj'hello' 'world' → 'ow'. [adj] is used by [expr]
to check the binding of adjancent kinds, and by [join] to determine whether to
blank-separate adjacent tokens such as names and numbers.
[name] extracts the name part of a definition: name' this ← that' → 'this'.
[redef] implements the re-definition option: ]defs name ← defn.
[tree] implements the top-down and refs tree displays. The two cases are similar
enough to warrant sharing the majority of the code. Differences are parameteris-
ed using operators T and R, which conditionally apply their operand functions,
depending on whether _l=1 (topdown) or ¯1 (refs). The function calls →externs←
so that local names in dfns are not counted as external references.
Requires: →externs← →in←
Examples:
avg ← (sum←(plus←+)(fold←⌿)) ÷ (num←≢) ⍝ some definitions ...
davg ← {(sum÷num)⍵}
dup ← {⍵ ⍵}
each ← {⍺←⊢ ⋄ ⍺ ⍺⍺¨⍵}
dups ← dup each
same ← (succ←one∘plus)∘(pred←-∘(one←1))
isnum ← ∊∘(digs←'0123456789')
twice ← {⍺⍺ ⍺⍺ ⍵}
greet ← 'hello'twice
that ← {this ⍵}
this ← {that ⍵}
⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝ Listing with names
1 defs '' ⍝ all defns
avg ← sum÷num
davg ← {(sum÷num)⍵}
digs ← '0123456789'
dup ← {⍵ ⍵}
dups ← dup each
each ← {⍺←⊢ ⋄ ⍺ ⍺⍺¨⍵}
fold ← ⌿
greet ← 'hello'twice
isnum ← ∊∘digs
num ← ≢
one ← 1
plus ← +
pred ← -∘one
same ← succ∘pred
succ ← one∘plus
sum ← plus fold
that ← {this ⍵}
this ← {that ⍵}
twice ← {⍺⍺ ⍺⍺ ⍵}
1 defs 'same' ⍝ "same" with names
same ← succ∘pred
⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝ Top-down indented display:
1 1 defs 'avg' ⍝ top-down defns of "avg"
avg ← sum÷num
sum ← plus fold
plus ← +
fold ← ⌿
num ← ≢
1 1 defs '' ⍝ all defns top-down
avg ← sum÷num
sum ← plus fold
plus ← +
fold ← ⌿
num ← ≢
davg ← {(sum÷num)⍵}
dups ← dup each
dup ← {⍵ ⍵}
each ← {⍺←⊢ ⋄ ⍺ ⍺⍺¨⍵}
greet ← 'hello'twice
twice ← {⍺⍺ ⍺⍺ ⍵}
isnum ← ∊∘digs
digs ← '0123456789'
same ← succ∘pred
succ ← one∘plus
one ← 1
pred ← -∘one
that ← {this ⍵}
this ← {that ⍵}
avl←{(⍳×/1↓⍴⍵)~⍵×⊃⍺⌷⍺⍺} ⍝ some dfns
box←{⍵⌿⍵/⍵ ⍵⍴⍳⍵×⍵}
cmap←{⊂[⍳⍴⍴⍵]1∊¨⍵∘.=⍵}
emt←{(,⍵=0)/,⍳⍴⍵}
nxt←{(⍺(⍺⍺ avl)⍵)⊣@(⊂⍺)¨⊂⍵}
nxtv←{⊃,/⍺∘(⍺⍺ nxt)¨⍵}
rcb←{(⍳⍵),¨box⊃⍵*÷2}
sfmt←{⊂[3 4]1 3 2 4⍉(2/(⍴⍵)*÷2)⍴⍵}
sudoku←{sfmt⊃cmap∘rcb svec ⍵}
svec←{⊃(⍺⍺⍴⍵)nxtv/(emt ⍵),⊂⊂⍵}
1 1 defs 'sudoku' ⍝ top-down display
sudoku ← {sfmt⊃cmap∘rcb svec ⍵}
sfmt ← {⊂[3 4]1 3 2 4⍉(2/(⍴⍵)*÷2)⍴⍵}
cmap ← {⊂[⍳⍴⍴⍵]1∊¨⍵∘.=⍵}
rcb ← {(⍳⍵),¨box⊃⍵*÷2}
box ← {⍵⌿⍵/⍵ ⍵⍴⍳⍵×⍵}
svec ← {⊃(⍺⍺⍴⍵)nxtv/(emt ⍵),⊂⊂⍵}
nxtv ← {⊃,/⍺∘(⍺⍺ nxt)¨⍵}
nxt ← {(⍺(⍺⍺ avl)⍵)⊣@(⊂⍺)¨⊂⍵}
avl ← {(⍳×/1↓⍴⍵)~⍵×⊃⍺⌷⍺⍺}
emt ← {(,⍵=0)/,⍳⍴⍵}
⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝ Bottom-up dependencies:
1 ¯1 defs 'plus' ⍝ defns dependent on "plus"
plus ← +
succ ← one∘plus
same ← succ∘pred
sum ← plus fold
avg ← sum÷num
davg ← {(sum÷num)⍵}
1 ¯1 defs 'one' 'plus' ⍝ defns dependent on "one" and "plus"
one ← 1
pred ← -∘one
same ← succ∘pred
succ ← one∘plus
plus ← +
sum ← plus fold
avg ← sum÷num
davg ← {(sum÷num)⍵}
⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝⍝ changing definitions:
defs 'plus ← -∘-' ⍝ redefinition of "plus"
0 defs 'same' ⍝ change to "plus" has changed "same"
same ← 1∘(-∘-)∘(-∘1)
0 defs defs 'div←÷' ⍝ new definition "div"
div ← ÷
See also: externs dft tacit in
Back to: contents
Back to: Workspaces