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":

avg ← sum÷≢

    )erase sum

avg ← +⌿÷≢

Likewise, _changes_ to the definition of "sum" will not change the behaviour of

    sum←+⌿          ⍝ reinstate definition of sum

    defs'avg'       ⍝ display of avg incorporates the definition
avg ← sum÷≢

    avg 1 2 3 4     ⍝ avg gives expected result
    sum←?           ⍝ change the definition of sum

    avg 1 2 3 4     ⍝ behaviour of avg _unchanged_
    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_

    defs 'jj'                   ⍝ [defs] displays _names_
jj ← ii ii ii


    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

        ]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

        ]fix fold←⌿         ⍝ fix this defn and its dependents

        ]fix -v fold←⌿      ⍝ -verbosely
    fold ← ⌿
     sum ← plus fold
     avg ← sum÷num


        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,

    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

    [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.


        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

    [join] concatenates its argument expressions with a blank  between  adjacent
    names or numbers.

Requires: ⎕SE.Dyalog.Utils.repObj


    sum ← +⌿
    num ← ≢
    avg ← sum÷num

    ]defs -c avg
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