Subject: Re: Hilbert Matrix
From: richard.levine@canrem.com (Richard Levine)
Date: Mon, 21 Aug 95 12:25:00 -0500
Organization: CRS Online  (Toronto, Ontario)

In article <60.5401.4394.0N1EEC5F@canrem.com> richard.levine@canrem.com
(Richard Levine) writes:
   The hook, fork, conjunctions, and cap used together in this
   expression [for perm] HAVE THE NICE PROPERTY that a
   reference to the argument y. in the middle of the expression
   IS NOT NECESSARY.

   perm =. 1 0&$`([: ,/ 0&,.@($:&.<:) {"2 1 \:"1@=@i.) @. *

bevan@cs.man.ac.uk (Stephen J Bevan) on Date: 11 Aug 1995 10:32:27 GMT
writes:
I don't disagree with the sentiment but it does leave unstated why
this is a nice property -- something I don't believe is immediately
obvious.

richard.levine@canrem.com comments:
Good point.  Thanks for your comment.
I was referring to the nice properties of tacit definition, and by
implication, the value of learning to write definitions tacitly.  In
order to develop this idea for myself, I wrote up some notes, and for
those interested in pursuing the discussion further, I have appended
these notes below.

---R.

NICE PROPERTIES

The properties of tacit definition were not immediately obvious to me,
but now they are.  Here below are some ideas which several people have
communicated to me in various ways, and I record below.

The expression under discussion was an example of tacit programming.

K. Iverson, in "A personal view of APL" (IBM Systems Journal, Vol. 30,
No. 4, 1991) writes:
<quote>
.. a tacit definition is one in which no explicit mention is made of the

arguments of the function being defined ...

... Tacit programming offers several advantages, including the
following:
1.  It is concise.
2.  It allows significant formal manipulation of definitions.
3.  It greatly simplifies the introduction of programming into any
topic.
<end of quote>

Notes:
1. tacit definitions are certainly concise
2. the formal manipulation apparently includes ability to simplify by
interpreter, automatic computation of inverses, and some efficiencies in

execution
3. the usual example of mean =. +/ % # is a simple example of
introducing a computation that in most languages requires at least a
simple program, but in J just requires essentially the statement of the
functions involved, without any extra baggage like "open function
definition", "show formal parameters", "close function definition" and
so on.

As a start, I have found simple tacit definitions (and tacit
expressions, if I can call them that) to be very useful.  For example,
to compare the results of two functions f and g for any argument x, it
is quite easy to write:

(f -: g) x   NB. does the result of f match the result of g
or
test =. f -: g
test x

instead of

(f x) -: (g x)  NB. 2nd parenthesis pair not necessary
or
write a test function

After I change f or g, and if x is a list of values, and either f or g
do not accept list values, I can easily write:

test"0 x

To actually display the results of f and g (and more functions) I simply

write:

(f ; g ; h) x

rather than ...

(f x);(g x);(h x)

I find simple tacit expressions quite convenient and useful, and have
starting "wishing" that APL's had them.  (PS. I still like and use
APL's.)

I guess all this is not to suggest that one cannot end up writing tacit
programs that are every bit as difficult to understand as difficult
explicit programs, but that is a matter of style and taste and is not
essential to tacit programming.

In so far as the ability of J to support writing tacit definitions, I
think it relates to the combination of the following language features,
each of which is a powerful feature on its own.

1.  the ability to assign a name to any expression, e.g.
    sum =. +/
    scan =. /\

2.  the large number of operators for composition of verbs, e.g.
    bond =. &
    compose =. &
    appose =. &:
    atop =. @
    at =. @:
    under =. &.
    Power =. ^:

3.  the lack of restrictions in applying verbs to operators, due in part

to the power of "permissive assembly" of results e.g.
    ,/  NB. ravel reduction ("insertion")
    f/  NB. defined function reduction ("insertion") for any function f
    most verbs can be used with operators

4.  the rank conjunction

5.  the fact that the parser recognizes trains, e.g.
    (f ; g ; h) as shown above
    (many examples of hooks and forks which are verb trains)

6.  special primitives that help in writing tacit expressions
    [:  cap
    $:  self-reference

7.  long left scope for the left argument of operators
    - helps to reduce required parentheses

8.  two operators which are the same except for syntax
    - same arguments, same result, but ...
    - adverb is strictly monadic
    - conjunction is strictly dyadic

All these features together have the nice property of being able to
express quite significant definitions concisely.

For a much more thorough discussion of tacit programming, I highly
recommend the article by D. McIntyre, "The Role of Composition in
Computer Programming" in the APL95 Conference Proceedings.  I found that

it serves as a tutorial on the entire subject of tacit programming in J
-- how to recognize and take apart tacit programs, how best to display
them, where they can be used, the important role of the fork and how to
recognize it, the importance of composition conjunctions (operators) in
writing tacit expressions, lots of sophisticated examples, and so on.

-- R.
