PrimitivePrimitives
Contents
Goal
If one of the primitives in the Vocabulary were missing, how would you reproduce its functionality? The goal is to get the definition of every primitive using other primitives.
Motivation
Besides being a fun puzzle, the primary motivation is pedagogical. These definitions can be used to generate sets of 'primitive primitives': J words that can be used to describe all the rest of J, providing an easy path to learning J.
Another nice side effect will be that some phrases/idioms/compoundcodesequences which are often repeated will become obvious (for example i.@:#). These pieces of code could be treated as primitives in their own right, leading to even more ways of expressing J within J. And, as a bonus, these idioms might be optimized in the interpreter, or even assigned to true primitives (as I. =. # i.@:# was).
Methodology
1.#0 We'd like an __exact__ replacement for each primitive. Specifically, the replacement should produce identical results under nominal conditions (even in internal type) to the original, and produce the same errors under exceptional conditions.
1. However, subfunctional replacements are acceptable, as they can be combined to produce a fully functional replacement.
1. Try not to use replacements for primitives within the replacements themselves. For example, in the replacement of ~., use only #~ ~:, not #~ (i.@:# = i.~), (substituting for ~:), #~ (i.@:# = ((#@:[ (>:@:[  <:@:) (i.~ .)~ ))~) (substituting for i.), etc. We'll have code that will automatically explore those relationships.
1. At a later point, we're going to have to think about inverses, identity functions, adverses, tolerance, and derivatives, too. Basically any other characteristic of the primtive built in to the interpreter (accesible via b., D., or !. ?).
1. Tacit code is preferred, but the removal of the Trains Table from Appendix F of the DoJ in version 5 has made this harder. I doubt many operators (adverbs/conjunctions) will be expressible tacitly.
1. Keep in mind that verbs can be monadic, dyadic, or ambivalent. When writing a replacement, indicate which of these cases you are replacing (and, for operators which produce verbs, indicate the valence of the __derived__ entity).
1. If you see a phrase that is oft repeated, feel free to give it a name, and substitute the name for the code in the defitions. Be sure to document the definition of the name somewhere! An example might be count =. i.@:# and substituting #~ count = i.~ for #~ i.@:# = i.~ in the redefinition of ~..
1. Primitives with many possible replacements might be better placed on a seperate subpage.
Comments
See the discussion page for more details. Yours are welcome.
Table of primitive replacements
Primitive  Valence  Replacement  Domain  Notes 
i:  Monad  ~ i.@:>:@:+:  Full  
Dyad  <:@:) (i.~ .)~ )  
{  Monad  >@:(,&.>/&.>/)  See notes  Does not work with an argument with (L. > 0: *. 1: = #) 
~.  Monad  #~ ~:  Full  
{.;.1~ ~:  
{./.~  
~:  Monad  i.@# e. i.~  Full  Nubsieve seems dependent on the pseudo primitive i.~ 
i.~ = i.@#  
i.@:# e. (i. ~.)  
i.@:# e. ] {./. i.@#  
Dyad  .@:=  Not equal  
/.  Dyad  1 : 'u.@#~ ='  Full  This was much neater in J4, where you could write (@(#~)) = 
+  Dyad    Full  
  Monad  0&  Full  Monad and dyad are defined in terms of each other. 
Dyad  +   
[  Ambivalent  ]~  Full  
]  Ambivalent  [~  Full  
@:  Ambivalent  2 : '[: u. v.'  Full  
,.  Ambivalent  ,"_1  Full  
~  Ambivalent  1 : '(] u. ]) : (] u. [)'  Verbs  
N/A  1 : 0  Nouns  
if. . 0 > nc n. =. {.;: m. do.  
". 'n.=.',5!:5 n.  
n.  
else.  
(13!:8) 4  
end.  
)  
L.  Monad  (>:@:(>./)@:($:&>))`0:@.((0: e. $) +. (: >))  Full  L. has no dyadic case as of J5, so this should be a complete replacement 
I.  Monad  # i.@:#  Full  I. has no dyadic case as of J5, so this should be a complete replacement 
..  Ambivalent  2 : '((u. + u.&v.) % 2:) : [:'  Full  Even though the DoJ says u .. v ⇔ (u + u&v) % 2:, verbs derived from .. have no dyadic case. 
.:  Ambivalent  2 : '((u.  u.&v.) % 2:) : [:'  Full  Even though the DoJ says u .: v ⇔ (u  u&v) % 2:, verbs derived from .: have no dyadic case. 
=  Monad  :@:(=/ ~.)@:,@:(<"_1)  Full  Using the dyadic case of = to define its monadic case. That is OK. We could also use i.~ in place of ,@:(<"_1) as Roger points out. 
Dyad  .@:~:  Making a cycle between the dyads = and ~:  
:  Monad  %&2  Full  
Dyad  =&:<  Could also use =&< but I'd rather use &: and define & in terms of &:. Similarly for the use of @: vs @.  
0:`(*./@:(=`(0: = +&:#) ($:&>)@.(+&:(=&32)&:(3!:0)))&:,)@.(0:`(*./@:=)@.(=&:#)&:$) 
See thread describing reimplementation of match  
<  Monad  a:&(] L: 0 _)  Full  Box 
{.@:;&0  
Dyad  .@:>:  Less than  
>  Monad  {.@:]^:(0: = L.@:]) ] S: _1  Full  Open 
Dyad  .@:<:  Greater than  
0 ^ 0 ^   Reported by Andrew Nikitin here, who cites Two Notes on Notation by Knuth.  
<.  Monad  Reals (not complex)  Floor. I'll get to complex in a minute (it's spelled out in the dictionary)  
<:@:>.  
Dyad  >: { ,  Full  Min  
<: { ,~  
, +/@:* 2: i.@:* _1: ^ <:  
>.  Monad  )  Reals (not complex)  Ceiling, I'll get to complex in a minute (it's spelled out in the dictionary) 
>:@:<.  
Dyad  <: { ,  Full  Max  
>: { ,~  
, +/@:* 2: i.@:* _1: ^ >:  
<:  Monad  &1  Full  Decrement 
Dyad  < +. =  Less or equal  
>:  Monad  +&1  Full  Increment 
Dyad  > +. =  Greater or equal  
_:  Ambivalent  _"_  Full  Similarly for _9:, _8:, _7:, _6:, _5:, _4:, _3:, _2:, _1:, 0:, 1:, 2:, 3:, 4:, 5:, 6:, 7:, 8:, and 9: 
#.  Monad  2&#.  Full  See rshp in the helper function section. Needed to satisfy the sentence "An atomic argument is reshaped to the shape of the other argument." in the definition of dyadic #. in the Vocabulary (1508 100 qdoj '#.'). 
Dyad  (+/@:* */\.@:}.@:,&1)~ rshp  
Monad  ."1  Full  See polynomial inverse on the J forums  
Dyad  ."1  scalar x ('':$@[)  
#  Monad  {.!.1@:$  Full  Tally is count of first dimenstion 
+/@:(1:"_1)  Tally is number of items. (could replace 1: with 1 to save ourselves a primitive)  
1 #. 1"_1  
E.  Dyad  [ :"_ _1 (];.3~ $)~  Full  E. has no monadic case as of J6, so this should be a complete replacement. See Splitting string on pattern and the earlier E. sensitive to type of empty vector LHA threads in the Forums. 
.  Monad  /: i.@@#  Full  Hook 
  Monad  %:@* +  Full  By definition 
% *  From Zero Divided by Zero by Eugene McDonnell  
>.   real numbers  Idea from A Formal Description of System/360, Table 1, "Notation", pp. 200. by KenIverson  
Dyad  ~^:<:^:_ or {:@:(#:~ 0&,)~  Full  
.  Monad  ~ 1:  Full  By definition 
1 0&I.  boolean (*./@e.&0 1)  booleans are the most common application of .  
%  Monad  %~ 1:  Full  
Dyad  * %  Full  
<.@%  Dyad  ([: <:@# ~^:<:^:(<_))~  
[.  Conj.  L=: 2 : 'u.'  Full  Lev, eg k=: + L m=:  L n=: * 
].  Conj.  D=: 2 : 'v.'  Full  Dex 
]:  Adverb  Id=: 1 : 'u.'  Full  Identity 
A.  Monad  (( i.)@#@x: #. +/@({. > }.)\."1)@(i.~ /:~)  Full  See Essays/Permutation Index 
Dyad  (/:^:2:@,/"1@(( i.)@#@x:@] #: [) i.@#) { ]  See Essays/Permutations  
(] + <:)/\"1@(#:~ ( i.)@#) { ]  See PermRevLexRank  
~) !@<:@#) (({~ {.)~ , {:@[ $: ({~ <^:3:@{.)~) ])^:(1: < #@]) 
Full  See Essays/Anagram  
e.  Monad  e.&>~/ ;  Full  =/~ for open y 
Dyad  +./@:(:"_ _1)"_1 _  Full  +./@:(:"r/)~ for item rank r  
e.  Monad  e.&>~/ ;  Full  =/~ for open y 
Dyad  +./@:(:"_ _1)"_1 _  Full  +./@:(:"r/)~ for item rank r  
+.  Dyad  ~ , ]) <./)@:,  Positive integers.  GCD. Algorithm stolen from the second APL image on this page 
i.  Monad  ([:> +/&.>/)@((* _1++/\@#&1)&.>~ 1,~[:*/\.}.)  not $0, no negative dimensions  scalar: _1++/\@#&1 
)"1  full  
($ (,~ <:@:{.)^:]@:(*/))  no negative dimensions  iterative (similar solution exists for recursive with $:)  
+/\&.:>:@:#&0  no negative dimensions  Nice use of &. due to RE Boss  
Dyad  [: +/ [: *./\ ~:  scalar x, vector y  
#@[  [: +/ [: +/\. =/  vector x, vector y  posted by Roger in the Forums  
4 : '(#x)  +/"1 +./\"1 x =/&:(<"(0>.<:#$x)) y'  uninvestigated  Posted by Roger Hui.  
,  Monad  {~ (<@#: i.@:(*/) )@:$  [: . 0 e. $  
Dyad  none  
<<Anchor(<;._3)>> <;._3  Dyad  :\&>~ ({~ #@:$))^:(#@:[) <  [: . 0 e. [  I think that ;._3 is wrong when 0 e. [ . If that's changed in the implementation, this replacement will have the complete domain.

\  Dyad  (;._3) (,@:) (" 0 _)  [: . 0 e. [  See notes re: domain at cut 3 reimplimentation 
#^:_1  Dyad  . ] # ({.~ #) ) (0 j. [ i. 1:) 
Full (but no !.)  See APL expand in J thread in the Forums. (As Henry Rich pointed out, we can treat #^:_1 as a [unnamed] primitive.) 
:  Monad  .@:$ $ ,  2<#@$@]  : : .@:$ $ ,) i. 2 2 
. $ (#. . .@#: i.@:(*/)))@:$  full  
Dyad  ({$) $"1 ] ,;.1~ (((1;'') {~ e.~) i.@:#@:$)  0 = L.@[  :; it just needs some work. Could replace ;.1 with ;.2.  
{.  Monad  ''&$ (($,)~ }.@$) 
nonempty y  
j.  Monad  0j1&*  Full  
Dyad  + j.  Uses own monadic definition; that's ok. Ambivalent replacement to j. would be 0j1&* : (+ $:)  
*  Monad  Full  Zero Divided by Zero by Eugene McDonnell  
D. 1  ~:&0  See wikipedia on abs. This article defines D.1 : (%) except at 0. But since we have 0%0 then I think D.1]0 should be 0 (but J gives 1 instead)  
(><)&0  Real numbers (i.e. 0={:@+.)  See [[../../papers/algebra.htm#A.2Algebra as a Language (Table A.1, 3rd entry)]]  
Dyad  +&.^.  Full  Classic sum under log  
#.@(*#:)  Positive integers  "Ethiopian multiplication" or "Russian peasant multiplication"; this terse formulation is due to Arie Groeneveld  
/:  Dyad  /:~i.@#  Full  Dyad defined in terms of monad (as opposed to other way around in DoJ) 
.@\:~  
\:  Dyad  \:~i.@#  Full  Dyad defined in terms of monad (as opposed to other way around in DoJ) 
.@/:~  
,:  Ambivalent  ,&.<  see note  Not yet analyzed, but if the dyad has a scalar argument, the equivalence only holds with certain ranks (or shapes?) of the other argument. 
}.  Monad  {~ i.&.<:@#  0 < #  There are obvious ways to implement }. in general (both monad and dyad), I just think this is a cute use of &. 
%:  Monad  :&.^.  Full  Obviously, the monads could be expressed in terms of the dyad (2 & (^@:(%~^.)) or (^%)&2) or the verb could even be made ambivalent 2&$: : (^@:(%~ ^.)). But the first formulation of the monad is a cute use of under. 
^&0.5  
(] :@+ %)^:_&1  Nonnegative numbers  
Dyad  ^@:(%~ ^.)  Full  
^%  
p.  Dyad  ."1)~  Full  If we consider all primitive replacements to be acting at the same rank as the original primitive (i.e. if the substitution s for p is understood to have an implicit "p as in s"p) then the rank specifications are unnecessary and may be elided.

?  Dyad  {. ?@!@x: A. i.  x<:y  A example of a J mapping well onto an English expression of a concept: "Take the first N values from a random rearrangement of the range 0..M1". Again, this replacements assumes that rank 0 is implied (i.e. the ranks of the reimplementation are artificially fixed to the ranks of the primitive, if they don't fall out that way naturally). 
Helper functions
Reshape Atomic Arguments:: See dyadic #. in the table above.
raa =. ,&< ($&.>~ ((.@:] {"_1 [ :@:,: ({~ 1: <. i.&1)) (#&>)) ) ,&:<&:$ rshp =: ((&:>) /) (@: raa f.)