Alexander Epifanov wrote:
> but I did not understand what is the different,
> I mean how it works if it is adverb.
To understand this error, we must first discuss what adverbs are, how they
behave, and how they differ from verbs. So let's start there.
----------
Adverbs are a different class, or order, of words than verbs. In
particular, they have higher grammatical precedence than verbs, and so
gobble up any suitable arguments lying around before verbs can even see
them. Conjunctions are in this same high-precedence class, but whereas
adverbs only take one argument (on the left), conjunctions take two (one on
the left, the other on the right). You can think of adverbs and
conjunctions as higher-order analogs to monadic and dyadic verbs
respectively.*
Adverbs are called adverbs because they normally modify verbs: that is, in
typical use, they accept a verb argument and produce verb result, which is
related in some (consistent) way to the argument. The most famous example
is / :
+/ 2 3 4 NB. Sum of data (Σ s[i])
*/ 2 3 4 NB. Product of data (Π s[i])
^/ 2 3 4 NB. Tetration ("power tower") of data
Here, / takes a dyad (two-argument verb) as an argument, and produces a
monad (one-argument verb)*. The output is related to the input in the
following sense: when the output verb is provided an noun, it inserts the
input verb between each pair of items in the noun, such that:
+/ 2 3 4 is 2+3+4
*/ 2 3 4 is 2*3*4
^/ 2 3 4 is 2^3^4 NB. Note: J executes right-to-left, so this
is 2^(3^4)
and
+/ 2 3 4 , 5 6 7 ,: 8 9 10
is:
2 3 4
+
5 6 7
+
8 9 10
which, because + is rank 0 (scalar), is:
2 3 4
+ + +
5 6 7
+ + +
8 9 10
etc.
But bear in mind that taking verb arguments and deriving (consistently)
related verbal results is only the typical case for an adverb. Adverbs can
also take a noun for an argument (an "adjective"); the most common example
is } , which normally takes a noun argument specifying which indices the
derived verb should modify (when it, itself, is applied to nouns):
putFirst =: 0}
putLast =: _1}
putFirstAndLast =: 0 _1}
'*' putFirst '12345'
*2345
'*' putLast 'ABCDE'
ABCD*
'*' putFirstAndLast 'ABCDE'
*BCD*
So adverbs can take verbs or nouns as inputs, and normally produce verbs as
outputs. But adverbs are not restricted to verbal output; they can produce
anything, including verbs, nouns, and even other adverbs and conjunctions.
Primitive adverbs which produce non-verb results are unusual (primitive
conjunctions are a little more diverse in this regard), but they exist. For
example, when the adverb ~ is applied to a string, it treats the string in
as a name and evokes it, such that 'someName'~ is equivalent to someName
. Therefore ~ can produce anything at all:
someNoun =: 42
someVerb =: +
someAdverb =: /
someConjunction =: @
'someNoun'~
42
'someVerb'~
+
'someAdverb'~
/
'someConjunction'~
@
Of course user-defined adverbs will produce anything they're defined to
produce, so you can't know what they'll do without reading the definition or
documentation. That said, user-defined adverbs tend to follow the same
patterns as primitive adverbs: they're almost always abstractions over verbs
which produce verb results; sometimes they take noun arguments and/or
produce noun results, and only very rarely do they produce other adverbs or
conjunctions.
Ok, with that as a background, we're ready to discuss write_image and the
error you observed.
---------------
The word write_image falls into this "user defined adverb" category. The
reason it was defined as an adverb instead of a verb is so that it can
accept up to 3 arguments (filename, data to write, and a set of options like
image quality or scaling), whereas if it were defined as a verb, it could
accept no more than two arguments. Meaning if write_image had been defined
as a verb, it would have to find some way to pack two arguments into a
single noun, and unpack them inside the definition, which can sometimes lead
to convoluted code. Keeping it as an adverb with three distinct arguments
is very clear and clean.
But it does stymie attempts to use it like a verb, as you discovered. In
particular, when you embedded it in
(('small/'&, (write_image)~ ((3 3)&resize_image)@:read_image)@:>) i
, its higher grammatical priority caused the adverb to seek out an argument
immediately, and since the verb 'small/'&, was on its left and suitable
(because verbs are perfectly acceptable arguments for adverbs), the result
was that write_image bound with 'small/'&, .
Now, the specific coding style** of write_image prevented it from being
executed immediately (if it'd been executed, you'd know it, because you
would have gotten an error: write_image is expecting data [a noun] as an
argument, not a verb like 'small/'&,), but it also allowed the J interpreter
to infer that when it is executed, it will produce a verb.
So write_image woke up, looked around for an argument, found 'small/'&, ,
bound with it, and though it didn't actually execute, the J interpreter knew
its product would be a verb. Knowing this, J proceeded parsing the
sentence, found another verb ((3 3)&resize_image)@:read_image)@:>, and hit a
close paren. Since it had found two verbs in isolation (nestled inside a
cozy pair of parens), it interpreted the train as a hook. This is really no
different from the sentence (%~ i.) 10 where ~ immediately binds to %, the
product of that binding and i. form a hook.
After forming the hook, the interpreter it hit the noun i and applied the
hook as ('small/'&,write_image~ 3 3&resize_image@:read_image)@:> i .
The interpreter executed 3 3 resize_image read_image > i and got a result.
Up to this point, everything was fine. But now it came time to use the
results it had calculated, and actually execute write_image . That's where
the problem occurred: and it was exactly the error I mentioned earlier, that
the interpreter avoided by deferring the execution of write_image (you can
delay the inevitable, but you can't avoid it).
That adverb was written expecting that its argument be a noun, and refers to
m, which is the name for the noun argument to an adverb (or conjunction).
But given how you expressed your sentence, in this case argument to
write_image was a verb: 'small/'&, . Therefore m (the name for a noun
argument to an adverb) was undefined, yet write_image tried to use it
anyway.
J calls the use of undefined names a "value error". This is the same error
as when you type
someNameIHaventDefinedYet
|value error: someNameIHaventDefinedYet
in the session manager.
But a closer analogy is the value error you'd get if you tried to use x
(which names a left argument) in a monadic verb which only has a right
argument:
monad def 'x + y' 4
|value error: x
| x+y
You get a value error because x is undefined, and x is undefined because
monadic (valences of) verbs don't have the concept of a left argument: x is
literally meaningless.
Similarly, when write_image referred to the noun argument m, the J
interpreter balked: "What noun argument? Your argument is a verb, 'small/'&,
. I don't know what you're talking about." . The name for the
(non-existent) noun argument to write_image, m, was literally meaningless.
All because adverbs have higher precedence than verbs and can accept verbs
as well as nouns as arguments.
Well, actually, because Cliff decided to define write_image as an adverb so
he could have three separate arguments, without boxing. I know that's a lot
to digest. I'm not known for my laconic style (cf Roger Hui), but I hope
this helps.
-Dan
* Technically, all verbs in J are ambivalent; that is, they can be called
with either one argument (on the right) or two arguments (one on the right,
and one on the left). The words "monad"/"monadic" and "dyad"/"dyadic" are
just shorthand for the "one-argument valence of the verb" and "the two
argument valence of the verb" respectively.
Note that some valences of some verbs have empty domains, such as the dyad
~. or the monad E. or the monad 4 : 'x + y' etc. That doesn't mean the
valence doesn't exist; it does exist, but it rejects all arguments (a
generalization of the concept that e.g. + rejects any argument that's not a
number).
Now adverbs and conjunctions (collectively called operators) are analogous
to the monadic and dyadic valence of a verb respectively, but it is exactly
because of their higher grammatical precedence that there is no operator
analog to an ambivalent verb. That is, there is no operator that can take
either one argument or two arguments. Operators' higher binding power
requires that we treat these cases separately - and, incidentally, is the
reason adverbs (monadic operators) take their argument from the left, as
opposed to monadic verbs which take their argument from the right.
** The specific coding style that allowed the J interpreter to conclude
write_image would produce a verb without actually executing it was that it
mentioned x and y - which, by definition, refer to the noun arguments to an
explicit verb. Therefore write_image must produce an explicit verb, and x
and y refer to /its/ arguments.
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm