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