The centigrade verb was defined explicitly with the : conjunction. The term explicit indicates that the arguments to the verb in the definition are referred to explicitly by their names of x. and y. .
In a tacit definition the arguments are not named and do not appear explicitly in the definition. The arguments are referred to implicitly by the syntactic requirements of the definition. You have already used several tacit definitions.
plus =. + sumover =. +/ maxover =. >./ scale =. % >./ mean =. +/ % #
The above are all tacit definitions. They do not use : and do not refer to arguments by name. In some cases the tacit form of definition is much simpler and more obvious than the equivalent explicit definition. In more complicated situations, it may take a bit of experience before you are comfortable with a tacit definition. This is partly because you probably have experience with explicit forms of definitions and very little with tacit definitions. In addition, tacit definitions tend to be more concise and mathematical expressions of a definition, and it may be necessary to go through the more detailed steps of creating an explicit definition before the equivalent tacit definition becomes clear.
Let's revisit fahrenheit to see how it could be defined tacitly. Open the cf.ijs script and look at the fahrenheit definition.
fahrenheit =: 3 : 0 t1 =. y. * 9 t2 =. t1 % 5 t3 =. t2 + 32 )
You can start by cleaning up the explicit definition. Now that you are more comfortable with J you can combine these calculations into a single line.
fa =: 3 : '(y. * 9 % 5) + 32'
The parentheses are required because the calculation inside them must be done before the 32 is added.
Let's shuffle the definition a bit to make the steps in building a tacit definition a bit clearer.
fb =: 3 : '32 + ((9%5) * y.)'
The above could be read as: add 32 to nine-fifths times the argument.
So, you need an add32 verb and a ninefifthstimes verb. You can use the bond conjunction & to build these verbs tacitly. The bond conjunction with a constant left argument returns a derived monad that is the verb in its right argument with the constant left argument.
add32 =: 32 & +
This defines add32 as a monad that adds 32 to its argument.
add32 12 44 ninefifthstimes =: (9%5) & *
This gives a monad which multiplies its argument by 9%5.
ninefifthstimes 20 36
Combining these you have:
add32 ninefifthstimes 100 212
The atop conjunction @ combines two verbs into a derived verb that applies the right verb to its argument and then applies the left verb to that result.
(u @ v) y evaluates as u v y
Use the atop conjunction to combine your two verbs to create the final definition.
fc =: add32 @ ninefifthstimes fc 100 212 fc _40 _40 fc 0 32
Display the verb fc and note that its definition is dependent on the other two definitions.
fc +-----------------------+ �add32�@�ninefifthstimes� +-----------------------+
Sometimes after you have built up a tacit definition from smaller building blocks you realize you really don't want all those smaller definitions hanging around. The f. adverb takes a tacit definition and replaces names with their definitions.
fz =. fc f.
The adverb f. , like all adverbs, takes its argument on its left.
Look at fz to see the final definition.
fz +--------------------+ �+------+�@�+-------+� ��32�&�+�� ��1.8�&�*�� �+------+� �+-------+� +--------------------+
The system can display tacit definitions in several different forms. These options can be selected from the View menu. With box display you get the preceding display. The Box Display can be very useful in understanding tacit definitions. However, for now use the View menu to select Linear Display so that you will see the following:
fz 32&+@(1.8&*)
In comparing something as simple as a verb defined as +, the tacit definition is much simpler than the equivalent explicit definition. In the fahrenheit example it could be argued that the explicit definition was simpler, especially if you used the 1.8 directly instead of the 9%5 as does the tacit definition.
fx =: 3 : '32+1.8*y.' vs. fz =: 32&+@(1.8&*)
The real strength in tacit programming comes in more complicated transformations of the arguments, particularly when the arguments must be referenced several times. The following illustrates another use of tacit definition.
xmean =: 3 : '(+/y.) % #y.'
This is the mean that you ran across in the Fork section.
mean =: +/ % #
The tacit definition just uses the fork directly.
The fork could also have been used in the explicit definition, but would have required parentheses around the fork.
xmean =: 3 : '(+/ % #)y.'
One advantage of tacit definitions is that they are more easily manipulated in formal ways than are explicit definitions. For example, J can automatically derive the inverse of many tacit definitions. Let's try this with the fz tacit definition. The inverse of the Fahrenheit conversion is the centigrade conversion. The standard profile defines an adverb inverse.
fz =: 32&+@(1.8&*) cz =: fz inverse fz 100 212 cz 212 100 fz 0 32 cz 32 0
Tacit programming is very powerful, but there is no need to leap into it. It is important to know what it is and to start using it in simple cases as this is the best way to become more familiar with it.