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/compound-code-sequences 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. 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.

  2. However, subfunctional replacements are acceptable, as they can be combined to produce a fully functional replacement.
  3. 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.

  4. 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 !. ?).

  5. 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.
  6. 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).

  7. 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 ~..

  8. Primitives with many possible replacements might be better placed on a seperate subpage.

Comments

See Comments 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 AndrewNikitin here, who cites Two Notes on Notation by Knuth.

<.

Monad

- 1&|

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

+  1&([ - |)

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

2 p.~ |."1

Full

See polynomial inverse on the J forums

Dyad

p.~ |."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 EugeneMcDonnell

>. -

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

$:^:(1 < #)@:(#~ *)@:((|~ , ]) <./)@:,

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

((_ * *) ];.0 ($ [: I. 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

<;._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.

Also, I should work on making a minimal tacit replacement for ;._3 instead of <;._3. Ideally, we should replace ;. itself (which would have to be explicit).

\

Dyad

(;._3) (,@:) (" 0 _)

[: -. 0 e. [

See notes re: domain at cut -3 reimplimentation

#^:_1

Dyad

] (-@:{.@:+.@:{.@:] |. 
] # ({.~ #) ) (0 j. [ i. 1:)
 ,~ 1 j. #;._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<#@$@]

given verb does not work on arrays of rank 2 or higher -- see (|: -: |.@:$ $ ,) i. 2 2

, {~ (|. $ (#. |. |.@#: i.@:(*/)))@:$

full

Dyad

({$) $"1 ] ,;.1~ (((1;'') {~ e.~) i.@:#@:$)

0 = L.@[

Note: this isn't right (yet), even for all open x. Cases like 0&transpose and 1 2&transpose work, but 0 1 2&transpose do not. However, the expression is clearly related to |:; it just needs some work. Could replace ;.1 with ;.2.

{.

Monad

''&$
(($,)~ }.@$)

non-empty 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 EugeneMcDonnell

| 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 Algebra 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

Non-negative numbers

Dyad

^@:(%~ ^.)

Full

^%

p.

Dyad

(#."0 1 |."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.

Note also that this equation is derivable from the equivalence #.2&$: : (p.~ |."1) given in the entry for #., so this entry may be redundant. Another redundant, but interesting, observation is that since #.#:^:_1 then p.(#:^:_1"0 1 |."1)~.

See the derivation from an earlier discovery and an essay on calculating polynomials in APL where this is referred to as the "internal Ruf-Horn" method

?

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..M-1". 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.)

PrimitivePrimitives (last edited 2012-08-31 08:00:42 by RE Boss)