defns ← {space←⎕this} ##.defs names ⍝ ]defs with names. [defs] takes a vector or matrix of [names] of function expressions and returns a display of the definitions. It is similar to the user-command ]defs except that where possible [defs] displays the names, rather than the values, of the compon- ent parts of the expression. sum ← +⌿ ⍝ make two ... avg ← sum÷≢ ⍝ ... definitons ]defs -c avg ⍝ ]defs shows the value (+⌿) of "sum" avg ← +⌿÷≢ ¯¯ defs'avg' ⍝ defs shows the name "sum". avg ← sum÷≢ ¯¯¯ NB: The appearance of name "sum" in the display of "avg" indicates only that _at the_time_of_the_display_ there is a definition that matches the value of this component of the train. If the definition of sum changes, this will no longer be the case and "sum" will disappear from the display of "avg": defs'avg' avg ← sum÷≢ )erase sum defs'avg' avg ← +⌿÷≢ Likewise, _changes_ to the definition of "sum" will not change the behaviour of "avg": sum←+⌿ ⍝ reinstate definition of sum defs'avg' ⍝ display of avg incorporates the definition avg ← sum÷≢ avg 1 2 3 4 ⍝ avg gives expected result 2.5 sum←? ⍝ change the definition of sum avg 1 2 3 4 ⍝ behaviour of avg _unchanged_ 2.5 defs'avg' ⍝ but display of avg no longer references "sum" avg ← +⌿÷≢ Such considerations apart, [defs] can be helpful when developing trains that reference other trains. For large trees the ]boxing and ]defs displays soon become unmanageably large: ff←+ ⍝ tree of forks ... gg←ff ff ff hh←gg gg gg ii←hh hh hh jj←ii ii ii ]boxing -trains=def Was parens jj ⍝ boxing displays _values_ (((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++)(((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++)((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++ ]defs jj ⍝ ]defs displays _values_ jj←(((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++)(((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++)((+++)(+++)+++)((+++)(+++)+++)(+++)(+++)+++ defs 'jj' ⍝ [defs] displays _names_ jj ← ii ii ii (muse: It may be appropriate to extend the "]defs" user command with a "-names" modifier, and the ]boxing command with a "-trains=names" option, which would display names in function expressions. Notice that, as with regular ]defs, definitions can be corrected simply by changing and resubmitting relevant lines of the display. ]defs -names ⍝ some definitions with names avg ← sum÷num fold ← ⌿ num ← ≢ one ← 1 plus ← + pred ← -∘one same ← succ∘pred succ ← one∘plus sum ← plus fold Aaron Hsu suggests that ]defs should offer a "-refs" option, to display def- initions in an order such that each precedes those of any dependents. This would make it easier to maintain trains by resubmitting dependent definit- ions following a change above them in the ]defs display. Note that "-refs" implies "-names": ]defs -refs ⍝ all definitions in dependent order fold ← ⌿ num ← ≢ one ← 1 pred ← -∘one plus ← + succ ← one∘plus same ← succ∘pred sum ← plus fold avg ← sum÷num In the above display, after correcting one definition, "fold" say, we must resubmit dependent definition "sum" and definition "avg", which depends on that. Because of the order, the three lines can be corrected in the session and resubmitted in one interaction. Remember that dependent definitions, such as "sum" and "avg" above, must be resubmitted 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. ]defs -r plus one ⍝ definitions dependent on "plus" and "one" plus ← + sum ← plus fold avg ← sum÷num one ← 1 pred ← -∘one succ ← one∘plus same ← succ∘pred The following function implements "-refs" by post-processing the result of [defs] and taking subject names as an optional left argument: refs←{ ⍝ ]defs -refs name defs←↓⍵ ⍝ vector of definitions names←~∘' '¨{(∧\⍵≠'←')/⍵}¨defs ⍝ name from each defn patn←1↓∊{'|\b',⍵,'\b'}¨names ⍝ whole-name patterns nq←{(~≠\⍵=''''){⍺\⍺/⍵}⍵} ⍝ ignoring quoted literals df←{(0=+\1 ¯1 0['{}'⍳⍵]){⍺\⍺/⍵}⍵} ⍝ ignoring names inside dfns hits←patn ⎕S 0 1∘df∘nq¨defs ⍝ names in defs calls←hits{1↓(+∘⍳/¨⍺)⌷¨⊂⍵}¨defs ⍝ calls per defn graph←⍸¨↓⍉↑names∘∊¨calls ⍝ called-by graph ⍺←names[(⍳⍴graph)~∊graph] ⍝ leaf definitions 0∊(⊆⍺)∊names:⍬⊤⍬ ⍝ mis-spelled name: quit dfs←{⊃∇⍨/⌽(⊂⍺ ⍺⍺ ⍵),⍺ ⍵⍵ ⍵} ⍝ depth-first search tree←{⍺,⊂⍵⊃defs}dfs{⍵⊃graph} ⍝ dependency tree search lines←↑,/⍬∘tree¨names⍳⊆⍺ ⍝ dependent definitions trim←{(∨\∨⌿⍵≠' ')/⍵}{⌽⍺⍺⌽⍺⍺ ⍵} ⍝ without outer blank columns trim↑⌽∪⌽lines ⍝ defns in dependent order } Finally, a new user command "]fix" could reassign dependent definitions automatically: ]fix fold←⌿ ⍝ fix this defn and its dependents ]fix -v fold←⌿ ⍝ -verbosely fold ← ⌿ sum ← plus fold avg ← sum÷num where: fix←{⍺←0 ⍝ {verbose←0} fix definition ↑⍺/{⍎⍵,'⋄⍵'}¨⍵{ ⍝ re-execute dependent definitions all←defs ⎕NL 2 3 4 ⍝ all definitions dps←⍵ refs all ⍝ defns dependent on name ⍵ (⊂⍺),1↓↓dps ⍝ new and dependent definitions }~∘' '⊢(∧\⍵≠'←')/⍵ ⍝ name from 'name←defn' } ) Technical notes: [defs]' primary data type "NKTDs" is a vector of [Name Kind Defn Tree] 4-tuples, where: Name: character vector. 'avg' Kind: 2:nilad 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: [rdefs] takes an NKTDs vector for all names in the target namespace together with a left argument of target names therein. It returns an NKTDs vector for those targets, in which definitions have been reduced by substituting names for all sub-expressions identical to the names' referent values. [rdef] ap- plies [subs] under reduction to the NKTDs vector, whose items have been sorted into order of increasing size. This ensures that the largest possible substitution is made at each step of the reduction. [rdefs] is an O(×/d s*2) function, where d is the number of definitions and s the mean definition- tree size. [subs] takes a vector of NKTDs processed so far as a left accumulating 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. [in] see →in←. [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 the target names and all possible subs- titution candidates. Definitions bigger than the largest target definition are excluded. [prep] pre-processes nested (⎕CR) definitions by: disclosing 1-vectors, which arise from named primitive functions, and removing the "name←" identifier 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: It is difficult in some circumstances to deduce the kinds of train com- ponents from their ⎕CR forms. For example, the following trains are dis- tinct even though they 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: avg ← +⌿÷≢ ⋄ 1 ⎕NC 'avg' ⍝ kind-tree ┌───┬─┬─┐ │3 4│3│3│ └───┴─┴─┘ 1 ⎕NC¨ 'fg' ⍝ (f g from above) ┌─────┬─────┐ │3 3 3│2 3 3│ └─────┴─────┘ ) [linear] takes the reduced expression tree, together with its kind-tree, and re- turns the parenthesised form of the expression. It uses inner functions: [expr] traverses (tree defn) pairs for each reduced definition, joining sub- expressions with appropriate parentheses. [crep] takes an array value and returns a character vector representing an expression that evaluates to that value. It uses library utility function ⎕SE.Dyalog.Utils.repObj. [join] concatenates its argument expressions with a blank between adjacent names or numbers. Requires: ⎕SE.Dyalog.Utils.repObj Examples: sum ← +⌿ num ← ≢ avg ← sum÷num ]defs -c avg avg ← +⌿÷≢ defs'avg' avg ← sum÷num tax ← 1.1 tot ← tax∘× defs'tot' 'tax' tot ← tax∘× tax ← 1.1 See also: dft tacit in Back to: contents Back to: Workspaces