- •Foreword
- •1. Introduction
- •2. Culture Shock
- •3. Preliminaries
- •Notation Used in This Book
- •Terminology
- •Sentences (statements)
- •Word Formation (tokenizing rules)
- •Numbers
- •Characters
- •Valence of Verbs (Binary and Unary Operators)
- •How Names (Identifiers) Get Assigned
- •Order of Evaluation
- •How Names Are Substituted
- •What a verb (function) looks like
- •Running a J program
- •The Execution Window; Script Windows
- •Names Defined at Startup
- •Step-By-Step Learning: Labs
- •J Documentation
- •Getting Help
- •4. A First Look At J Programs
- •Average Daily Balance
- •Calculating Chebyshev Coefficients
- •5. Declarations
- •Arrays
- •Cells
- •Phrases To Memorize
- •Constant Lists
- •Array-creating Verbs
- •6. Loopless Code I—Verbs Have Rank
- •Examples of Implicit Loops
- •The Concept of Verb Rank
- •Verb Execution—How Rank Is Used (Monads)
- •Controlling Verb Execution By Specifying a Rank
- •Examples Of Verb Rank
- •Negative Verb Rank
- •Verb Execution—How Rank Is Used (Dyads)
- •When Dyad Frames Differ: Operand Agreement
- •Order of Execution in Implied Loops
- •A Mistake To Avoid
- •7. Starting To Write In J
- •8. More Verbs
- •Arithmetic Dyads
- •Boolean Dyads
- •Min and Max Dyads
- •Arithmetic Monads
- •Boolean Monad
- •Operations on Arrays
- •9. Loopless Code II—Adverbs / and ~
- •Modifiers
- •The Adverb Monad u/
- •The adverb ~
- •10. Continuing to Write in J
- •11. Boxing (structures)
- •Terminology
- •Boxing As an Equivalent For Structures In C
- •12. Compound Verbs
- •Verb Sequences—u@:v and u@v
- •Making a Monad Into a Dyad: The Verbs [ and ]
- •Making a Dyad Into a Monad: u&n and m&v
- •13. Empty Operands
- •Execution On a Cell Of Fills
- •Empty cells
- •If Fill-Cells Are Not Enough
- •14. Loopless Code III—Adverbs \ and \.
- •15. Verbs for Arithmetic
- •Dyads
- •Monads (all rank 0)
- •16. Loopless Code IV
- •A Few J Tricks
- •Power/If/DoWhile Conjunction u^:n and u^:v
- •Tie and Agenda (switch)
- •17. More Verbs For Boxes
- •Dyad ; (Link) And Monad ; (Raze)
- •Dyad { Revisited: the Full Story
- •Split String Into J Words: Monad ;:
- •Fetch From Structure: Dyad {::
- •Report Boxing Level: Monad L.
- •18. Verb-Definition Revisited
- •What really happens during m :n and verb define
- •Compound Verbs Can Be Assigned
- •Dual-Valence verbs: u :v
- •The Suicide Verb [:
- •Multi-Line Comments Using 0 :0
- •Final Reminder
- •The Obverse u^:_1
- •Apply Under Transformation: u&.v and u&.:v
- •Defined obverses: u :.v
- •An observation about dyadic verbs
- •20. Performance: Measurement & Tips
- •Timing Individual Sentences
- •Compounds Recognized by the Interpreter
- •Use Large Verb-Ranks! and Integrated Rank Support
- •Shining a Light: The J Performance Monitor
- •21. Input And Output
- •Foreigns
- •File Operations 1!:n; Error Handling
- •Treating a File as a Noun: Mapped Files
- •Format Data For Printing: Monad And Dyad ":
- •Format an Array: 8!:n
- •Format binary data: 3!:n
- •printf, sprintf, and qprintf
- •Convert Character To Numeric: Dyad ".
- •22. Calling a DLL Under Windows
- •Memory Management
- •Aliasing of Variables
- •23. Socket Programming
- •Asynchronous Sockets and socket_handler
- •Names and IP Addresses
- •Connecting
- •Listening
- •Other Socket Verbs
- •24. Loopless Code V—Partitions
- •Find Unique Items: Monad ~. and Monad ~:
- •Apply On Subsets: Dyad u/.
- •Apply On Partitions: Monad u;.1 and u;.2
- •Apply On Specified Partitions: Dyad u;.1 and u;.2
- •Apply On Subarray: Dyad u;.0
- •Apply On All Subarrays: Dyad u;.3 and u;._3
- •Extracting Variable-Length Fields Using ^: and ;.1
- •Example: Combining Adjacent Boxes
- •25. When Programs Are Data
- •Calling a Published Name
- •Using the Argument To a Modifier
- •Invoking a Gerund: m`:6
- •Passing the Definition Of a Verb: 128!:2 (Apply)
- •Passing an Executable Sentence: Monad ". and 5!:5
- •26. Loopless Code VI
- •28. Modifying an array: m}
- •Monad I.—Indexes of the 1s in a Boolean Vector
- •29. Control Structures
- •while./do./end. and whilst./do./end.
- •if./do./else./end., if./do./elseif./do./end.
- •try./catch./catcht./end. and throw.
- •return.
- •assert.
- •30. Modular Code
- •Locales And Locatives
- •Assignment
- •Name Lookup
- •Changing The Current Locale
- •The Shared Locale 'z'
- •Using Locales
- •31. Writing Your Own Modifiers
- •Modifiers That Do Not Refer To x. Or y.
- •Modifiers That Refer To x. Or y.
- •32. Applied Mathematics in J
- •Complex Numbers
- •Matrix Operations
- •Calculus: d., D., D:, and p..
- •Taylor Series: t., t:, and T.
- •Hypergeometric Function with H.
- •Sparse Arrays: Monad and Dyad $.
- •Random Numbers: ?
- •Computational Addons
- •Useful Scripts Supplied With J
- •33. Elementary Mathematics in J
- •Verbs for Mathematics
- •Extended Integers, Rational Numbers, and x:
- •Factors and Primes: Monad p:, Monad and Dyad q:
- •Permutations: A. and C.
- •34. Graphics
- •Plot Package
- •2D Graphics: the gl2 Library
- •Displaying Tabular Data: the Grid Control
- •3D Graphics: OpenGL
- •35. Odds And Ends
- •Dyad # Revisited
- •Boxed words to string: Monad ;:^:_1
- •Spread: #^:_1
- •Choose From Lists Item-By-Item: monad m}
- •Recursion: $:
- •Make a Table: Adverb dyad u/
- •Cartesian Product: Monad {
- •Boolean Functions: Dyad m b.
- •Operations Inside Boxes: u L: n, u S: n
- •Comparison Tolerance !.f
- •Right Shift: Monad |.!.f
- •Generalized Transpose: Dyad |:
- •Monad i: and Dyad i:
- •Fast String Searching: s: (Symbols)
- •Fast Searching: m&i.
- •CRC Calculation
- •Unicode Characters: u:
- •Window Driver And Form Editor
- •Tacit Programming
- •36. Tacit Programs
- •37. First Look At Forks
- •38. Parsing and Execution I
- •39. Parsing and Execution II
- •The Parsing Table
- •Examples Of Parsing And Execution
- •Undefined Words
- •40. Forks, Hooks, and Compound Adverbs
- •Tacit and Compound Adverbs
- •Referring To a Noun In a Tacit Verb
- •41. Readable Tacit Definitions
- •Flatten a Verb: Adverb f.
- •Special Verb-Forms Used in Tacit Definitions
- •43. Common Mistakes
- •Mechanics
- •Programming Errors
- •44. Valedictory
- •45. Glossary
- •46. Error Messages
- •47. Index
25. When Programs Are Data
One characteristic of maturity in programming is readiness to pass a program as an argument. A well-designed program does not exhibit a megalomanic urge to do everything the user may desire; it is content to perform a limited function well, and to leave other functions to other programs. A suite of such programs can be variously connected to perform a great variety of functions, with each program doing its bit and passing control to the next one.
In C a program is passed to another program by pointer reference, and invoked by (*pfi)(arguments). J has no pointers, but it has a great many ways to pass executable nuggets around the system. We will learn them now.
Calling a Published Name
The simplest way to get a verb f to pass control to another program g is to define f to call a verb with a public name, say f_subfn, and then to define f_subfn to be g . In C, this would be ridiculous, because it would imply that f_subfn is permanently bound to a single value of g, with the result that all calls to f from anywhere in your program would be stuck with the same value of g .
J overcomes this objection by allowing redefinition of f_subfn . Each invocation of f looks like
f_subfn =: g f arguments
When f is invoked elsewhere, the correct value of f_subfn will be assigned similarly, so each invocation of f can pass control properly.
I find this technique hideous, but I have to admit it is effective. J uses it to get callbacks from DLLs. It must not be used if f_subfn is going to be called in response to an event, since its value may have been redefined by the time the event occurs.
Using the Argument To a Modifier
If the verb isn't going to call a name of its own choosing, you have to tell it what to call. The simplest way to do this is to change the verb into a modifier; then when it executes it has access to its operands, which can be verbs. So, instead of
f =: verb : 'definition' you write
f =: adverb define monadic definition
:
dyadic definition
)
and within the definition of f you can refer to the left operand of the adverb, which goes by the name u. . If you decide to write a conjunction instead, its right operand is v. .
153
The noun operands of the derived verb (u f or u f v) are x. and y., as usual. We will discuss user-defined modifiers in a later chapter.
In Chapter 3 this technique was used to calculate the Chebyshev coefficients of a function. The function to be approximated is one of the inputs to this calculation, so we write an adverb and let its left operand be the function. With chebft defined as in the example, an example of its use is:
10 (2&o.) chebft 0 1
1.64717 _0.232299 _0.0537151 0.00245824 0.000282119…
Here the function to be approximated is the cosine function 2&o., evaluated for 10 Chebyshev coefficients over the interval 0 1 .
When you define a modifier, you have no way to specify that you are defining only the dyadic case as you can for a verb with dyad define . Instead, you use the form given above, in which the monadic definition (if any) is separated from the dyadic by a line containing a single ':' character. chebft did this, since its derived verb is always dyadic.
Invoking a Gerund: m`:6
Sometimes you want to use a noun rather than a verb to designate a verb to be called. An asynchronous socket handler is an example: the socket handler will have many transfers going on at once, each one with a callback to be executed when the transfer is complete. The callbacks must be put into a table along with other information about the transfer; in other words, the callbacks must be nouns.
We have already met nouns that carried verbs; we called them gerunds. We found that gerunds were created by the conjunction ` and executed by m@.v . While these tools are adequate to allow verbs to be passed as arguments, some simplifications are available that we will discuss now.
A gerund created by u`v is always a list (each element of which, as we learned, is an atomic representation of a verb which we will treat as untouchable). Even if there is only one verb, the result of ` is a list:
+`''
+-+ |+| +-+
$ +`''
1
It makes sense for the gerund created by ` to be a list, since it contains a list of verbrepresentations one of which is selected for execution by m@.v . But when we are passing a single verb-as-noun as an argument, it is OK for it to be a scalar box. And, it can be invoked using the `: conjunction: m`:6 converts the gerund m into a verb. So, in our example, we pass the callback as one box in a parameter list, and then we select it, turn it into a verb with m`:6, and execute it, as we can see in a stripped-down example. The gerund operations are not difficult so I am going to keep your interest with a couple of new tricks:
154
callback =: dyad : '(x.) =: y.'
Howzat? (x.) =:? Yeah, this means that the value of x. tells what variable will be assigned. x. can be any valid assignment target: a name, a multiple assignment, or other exotic forms given in the Dictionary.
calledfn =: monad : '(0 { y.)`:6 (1 {:: y.)'
So calledfn is expecting an argument of (at least) 2 boxes. The first one will be the gerund to execute, and the second one will be the argument to pass to that verb. We open the second box (with {::) but we leave the first as a box so that `:6 can turn it into a verb.
calledfn 'vbl'&callback ` (<25)
The first challenge is figuring out what the argument to calledfn is. ` sees a verb on its left; it converts that to a gerund. It sees a noun to its right, so it appends it unchanged to the gerund from the left. This produces
'vbl'&callback ` (<25) |
+ |
||
+---------------------- |
|
+-- |
|
|+-+------------------ |
+ |
+|25| |
|
||&|+------- |
+|| |
| |
|
|| ||+-+--- |
+|callback||| |
| |
|
|| |||0|vbl|| |
||| |
| |
|
|| ||+-+--- |
+| |
||| |
| |
|| |+------- |
+-------- |
+|| |
| |
|+-+------------------ |
|
+| |
| |
+---------------------- |
|
+-- |
+ |
The first box is the atomic representation of the verb, just as mysterious as it was billed to be, and the second box has the 25. Now what do we get when we pass that in as the argument to calledfn (try to work it out before you peek at the answer)?
calledfn 'vbl'&callback ` (<25)
25
Did you get it? We executed 'vbl'&callback 25 which then executed
vbl =: 25 which has the result 25, which comes back as the result of calledfn . The assignment was public:
vbl
25
Passing the Definition Of a Verb: 128!:2 (Apply)
As an alternative to passing a gerund and invoking it with m`:6, you could pass the string representation of a verb and make a verb out of it with 3 :n or 4 :n . Better yet, if you can make do with a monadic verb, you can use the foreign dyad 128!:2 which has rank 1 _ and goes by the name Apply. x 128!:2 y takes the string x which must describe a verb, and applies the verb so described to y (as a monad). It is therefore similar to (3 : 'x') y with the restriction that x must describe a one-line verb without assignments. The advantage of using 128!:2 rather than the method in the next section is that y does not have to be converted to its string representation.
155
Passing an Executable Sentence: Monad ". and 5!:5
As the ultimate in flexibility, you can pass an entire J sentence as a character string and then execute it with monad ". . It is executed exactly as if it had been a line of the executing verb (or from the keyboard if that's where ". was entered). For example:
". 'a =. i. 4' 0 1 2 3
The sentence was executed. a
0 1 2 3
The assignment was performed.
". '+/' , ": a
6
The operand of monad ". must be a string, so before we can take its total we must convert a to a sequence of characters that will have the value of a when executed. For a large operand, converting to string form adds overhead that might steer you towards using a gerund or 128!:2 instead.
I think C programmers are likely to overlook opportunities to use monad ". because it is so foreign to their experience. It is equivalent to compiling and executing a code segment as part of the running program—it's just unthinkable. But in J, it's commonplace.
If you are going to use monad ". you will face the problem of converting your nouns to string form. Here's the display of a noun: what character string would you execute to
produce a noun with that value? |
|
||||
+ |
a |
|
+ |
+ |
|
+ |
+ |
||||
|+--- |
+|0 2.25 4.5 6.75 9 11.25 13.5 15.75| |
||||
||abc|de|fgh|| |
| |
||||
|+--- |
+-- |
+--- |
+| |
| |
|
+------------ |
|
|
+---------------------------------- |
+ |
Fortunately, you don't have to worry about it. The foreign monad 5!:5 takes as y a boxed name (not a value) and produces a string which when executed has the same value as the variable named by y . So:
5!:5 <'a'
(<<;._1 ' abc de fgh'),<2.25*i.8
…and if you tell me you came up with the same string, I'm not going to believe you.
156