Operators in J
Explore arithmetic, comparison, boolean, and array operators in J — and discover how reduce, fork, and tacit composition replace traditional control flow.
In most programming languages, “operators” are a small, fixed set of infix symbols like +, -, and ==. In J, what other languages call operators are called verbs, and they are first-class citizens of the language. A J verb works on scalars and entire arrays with equal grace — 2 + 3 and 2 + 1 2 3 4 5 are equally idiomatic, and neither one needs a loop.
Because J is array-oriented and tacit, operators are also the primary tool for control flow. Reducing a list with +/ replaces a for loop that accumulates a sum. Filtering with # replaces an if inside that loop. Forks and hooks let you compose verbs into new verbs without ever naming an argument. This page introduces the core operator set and then shows how J builds bigger ideas out of small, dense pieces.
A few syntactic reminders that change how operators behave compared to mainstream languages:
- J evaluates expressions right to left with no operator precedence.
2 * 3 + 4is14, not10. - Many symbols are overloaded between monadic (one argument) and dyadic (two argument) forms.
-subtracts when given two arguments and negates when given one. - Negative literals use
_, not-._3is negative three;- 3is the verb-applied to3.
Arithmetic and Comparison Verbs
Create a file named operators.ijs:
| |
A few things to notice. Division uses % because / is reserved for the reduce adverb. The verb | is residue with x | y meaning y mod x — the left argument is the divisor, which surprises newcomers from C-family languages. Comparison verbs return 0 or 1, not a separate boolean type; that means you can do arithmetic on the results of comparisons, which is one of the secrets behind J’s terse expressions.
The reduce adverb / is where J starts to feel different. +/ 1 2 3 4 5 doesn’t loop — it inserts + between every adjacent pair: 1 + 2 + 3 + 4 + 5. The same pattern works for any verb: */ for product, >./ for max, <./ for min, *./ for “all true,” +./ for “any true.”
Tacit Composition: Building Verbs from Verbs
J’s most distinctive feature is tacit programming: defining new verbs by composing existing verbs, without ever referring to the arguments by name. The two core composition patterns are the fork (three verbs in a row) and the hook (two verbs in a row).
A fork (f g h) applied to y means (f y) g (h y). So (+/ % #) applied to a list means “(sum of list) divided by (count of list)” — the arithmetic mean.
Create a file named tacit.ijs:
| |
The line mean =: +/ % # reads like a mathematical definition: “mean is sum divided by count.” There is no argument named anywhere — the fork pattern wires the arguments through automatically. This is the same idea as function composition in Haskell, but pushed further: even basic arithmetic combinations like (max - min) are written without lambdas.
The ~ adverb is reflexive: it makes a dyadic verb act on the same value twice. *~ 7 becomes 7 * 7. The conjunction @: is compose: +/ @: *: first squares every item (*: is the verb “square”) and then sums them.
J has two assignment verbs: =: is global (the binding persists across the program), and =. is local (visible only inside the current verb definition). They are verbs themselves, which is why expressions like counter =: counter + 1 look symmetric — you really are applying a verb to counter and counter + 1.
Running with Docker
| |
J scripts (.ijs files) are interpreted line by line. Unlike interactive mode, scripts do not auto-display the value of an expression — you have to explicitly echo (or smoutput) anything you want printed.
Expected Output
Running operators.ijs:
-- Arithmetic --
5
6
42
2.5
256
1
-- Monadic --
_5
0.25
7
-- Comparison --
1
1
1
1
-- Boolean --
0
1
0
-- Arrays --
11 22 33
2 4 6 8 10
1 0 1 1
-- Reduce --
15
120
9
1
-- Precedence --
14
9
Running tacit.ijs:
mean of 1..5:
3
range of 3 1 4 1 5 9 2 6:
8
square of 7:
49
sum of squares of 1..4:
30
counter after three increments:
3
Note _5 rather than -5 — J writes negative numbers with a leading underscore so that the minus sign can be unambiguously interpreted as the verb - (subtract/negate).
Key Concepts
- Verbs replace operators. What other languages call operators, J calls verbs. They are first-class and can be assigned to names, composed, and modified by adverbs.
- Scalar extension is automatic. Any verb that works on numbers works element-wise on arrays of any rank. No looping required.
- Right-to-left, no precedence.
2 * 3 + 4is14. Parentheses override grouping; nothing else does. - Monadic vs dyadic overloading. Most symbols mean different things with one argument versus two.
-negates monadically, subtracts dyadically;%reciprocates monadically, divides dyadically. /is the reduce adverb.+/,*/,>./,<./,*./,+./cover sum, product, max, min, all, any. The same pattern works with any verb.- Tacit verbs compose without arguments. A fork
(f g h)applies the outer verbgbetween two inner applications; this lets you write definitions likemean =: +/ % #that look mathematical, not procedural. %is divide, not modulo. Modulo is|with the divisor on the left:3 | 10is1._is the negative sign._3is the literal negative three.-3is the verb-applied to3, which happens to give the same value but means something different.
Running Today
All examples can be run using Docker:
docker pull nesachirou/jlang:latest
Comments
Loading comments...
Leave a Comment