Analysis of information sources in references of the Wikipedia article "J语言" in Chinese language version.
In 1989, Iverson, together with Roger Hui and with input from Arthur Whitney, produced J, with a goal of providing a “shareware” APL implementation for use in teaching. The special APL characters were abandoned because it was felt that they require technical solutions which at that time were still prohibitively expensive in an educational environment. ……
J was clearly a “rationalization” of SHARP APL. ……
ACM SIGAPL, the ACM Special Interest Group on APL, reinterpreted the “APL” in its name in early 2009 as Array Programming Languages, so that J, k, Nial, etc. would be included in its purview.
Gerunds, verbal forms that can be used as nouns, are recognized as having utility in the realm of programming languages. We show that gerunds can be viewed as arrays of atomic repmentations of verbs (functions), in a way which is consistent with the syntax and semantics of APL, and which allows verbs to be first class objects in the language. We define derivations of verbs from gerunds in the J dialect of APL, and show how these derivations provide control structures for sequencing, selection (in the sense of generalized forms of CASE or SWITCH statements and IF/THEN/ELSE), iteration (DO UNTIL), recursion, and parallel computation (MIMD, or Multiple Instruction, Multiple Data). We conclude with alternative representations of verbs which are useful in other contexts.
`:1
replaced byu^:v
`:4
replaced bym~
`:5
replaced by@.
For years, Iverson struggled to achieve in APL the effect off+g
andf×g
as they are written in calculus. …… Finally, trains AKA forks were invented [Iverson and McDonnell 1989]. ……
Moreover,(f … h p q r) ↔ (f … h (p q r))
, and an isolated sequence of two functions is also assigned a meaning (atop, described below), so that a train of any length, even or odd, is interpreted. ……
Subsequently, it was realized that trains greatly increase the possibilities for “tacit definition”, expressions consisting of compositions of functions which do not explicitly mention the arguments [Hui et al. 1991]. Trains are implemented in several dialects: J [Hui et al. 1991], NARS2000 [Smith 2020], NGN APL [Nickolov 2013], and Dyalog APL [Scholes 2013]. ……
The expressive completeness of trains depends on an atop composition of two functions …… Dyalog APL defines 2-trains as atop. That, together with the functions⊣
(left) and⊢
(right), allows many common compositions to be written as trains.
The data structures of APL are rectangular, multi-dimensional, and flat -- the latter term meaning that all items of arrays are simple scalars. ……
In general, a system with nested arrays extends the power of APL by being able to represent data of non-zero depth. Also, in keeping with the past, the system includes a set of primitive functions and operators, tailor-made for manipulating these new data structures.
Continuing the above example, the names of the months of the year are best represented in a 12-item vector whose items are each character vectors. This structure has a depth of one. Note that because the individual names are in separate items, we need no longer resort to artifices like pad characters. Moreover, explicit delimiters are not needed as the separation between items is represented through structure rather than data. This particular representation is called a vector of vectors, and can be created as follows:
MONTHS ← ('JANUARY') ('FEBRUARY') ...
The above line also illustrates strand notation, used to enter a nested vector in a simple and convenient manner. ……
Of the several new operators, the only one specific to nested arrays is the each operator(symbol¨
), which is monadic as an operator, and produces an ambivalent derived function. It is used to apply the f unction which is its argument to the items of an array to produce corresponding items in the result. For example, to determine the length of the names of the months in the above example, use
⍴¨MONTHS
(7) (8) (5) (5) (3) (4) (4) (6) (9) (7) (8) (8)
Since monadic rho returns a vector , each item of the above result is a vector (specifically in these cases a one-item vector). The parentheses in the display indicate that the item is not a simple scalar.
In order to provide users with access to APIs and frameworks, APL language designers searched for ways to integrate into APL, where everything is an array, selected aspects of the OO paradigm, where everything is an object. ……
Some interpreters, like APL+Win, avoided incorporating objects into the APL heap (or “workspace”). ……
Other systems added features which allowed variables, functions and operators to be organized in dynamic objects in the workspace. The resulting containers are known as namespaces (Dyalog APL) and locales (J). k implements dictionaries, which are also containers for arrays, but are typically used to contain arrays representing the columns of a relational table. …… The same language features which supported namespaces or classes within APL were used to wrap the external objects used by object oriented APIs, or platforms like the Microsoft’s OLE and .NET frameworks.
The choice of syntax for referring to a membername
of an objectemp
was not straightforward. ……
Most APL systems did adopt the notation from other OO languages — with a few exceptions.
emp.name
in most APL systems
name__emp
in J (retaining right-to-left evaluation)
emp[`name]
in k (using a symbol within index brackets to select from a dictionary)
……
Although APL interpreters have had extensive support for object oriented programming for nearly two decades, most APL users still feel that object and array paradigms are an awkward fit. …… Many of the benefits of OO are related to taking advantage of types, while much of the strength of the APL family is that you can write code which is shape, rank, and type agnostic — achieving many of the same goals as OO through radically different mechanisms.
In the dyadic case, two frameslf
andrf
are involved, from the left and right arguments. Several different treatments are possible:
• scalar agreement:(lf≡rf)∨(lf≡⍬)∨(rf≡⍬)
, the left and right frames match, or one is the empty vector (⍬
). If the frames match, there are an equal number of left and right cells, and the operand function applies to corresponding cells. If they do not match, one frame must be⍬
, that is, there is one cell on one side, whence that one cell is applied against every cell on the other side. Scalar agreement is implemented in Dyalog APL [Dyalog 2015].
• prefix agreement:(p↑lf)≡(p↑rf) ⊣ p←(≢lf)⌊(≢rf)
, one frame must be a prefix of the other. Letff
be the longer frame (that is,ff←lf,p↓rf
). In this case a cell of the argument with the shorter frame is applied against×⌿p↓ff
cells of the other argument. Prefix agreement is implemented in J [Hui and Iverson 2004], and is consistent with the emphasis on the leading axis (§2).
• suffix agreement: one frame must be a suffix of the other. J had suffix agreement before it switched to prefix agreement in 1992 on a suggestion by Whitney [Whitney 1992].
• strict agreement: the frames must match. No dialect has ever implemented this.
One of the HOPL IV badges has an APL expression on it:÷+/÷(e≠0)/e
, the reciprocal of the sum of the reciprocals of the non-zero values ofe
. The expression computes the total resistance of components connected in parallel, whose resistance values are the vectore
.
There is an alternative phrasing in modern APL:+⌿⍢÷e~0
, sum under reciprocal (§3.5), without0
s. If arithmetic were extended to infinity (§4.6), in particular if÷0 ↔ ∞
and÷∞ ↔ 0
, then the expression would simplify to+⌿⍢÷e
, without the without0
(~0
).
This paper proposes two related extensions to APL: the extension of assignment to allow a nameF
to be assigned to a derived function by an expression of the formF←+.x
, and the introduction of a dyadic operator∇
to apply to character arraysD
andM
so thatD∇M
produces an ambivalent function in which the dyadic case is defined byD
and the monadic case byM
.
The proposed replacement for⎕fx
is a modification of the direct definition operator∇
defined in [A Function Definition Operator], ……
A function produced by the operator∇
may be assigned a name (as inf←m∇d
or ina(f←m∇d)b
), but it may also be used without assigning a name, as iny←''∇'⍺+÷⍵'/x
.
Well, we don’t know what Ken Iverson’s favorite APL expression was or if he even had a favorite APL expression. But we can guess. From A History of APL in 50 Functions [Hui 2016a, §8]:
⊢ x←,1
1
⊢ x←(0,x)+(x,0)
1 1
⊢ x←(0,x)+(x,0)
1 2 1
⊢ x←(0,x)+(x,0)
1 3 3 1
The expression(0,x)+(x,0)
or its commute, which generates the next set of binomial coefficients, …….
What is being indexed is an array (of course) but the indices themselves (the “subscripts”) can also be arrays. For example [Hui 2016a, §4]:
x← 3 1 4 1 5 9
'.⎕'[x∘.>⍳⌈⌿x]
……
In the example, the 2-element character vector'.⎕'
is indexed by a 6-by-9 Boolean matrix.
Quicksort works by choosing a “pivot” at random among the major cells, then catenating the sorted major cells which strictly precede the pivot, the major cells equal to the pivot, and the sorted major cells which strictly follow the pivot, as determined by a comparison function⍺⍺
. Defined as an operatorQ
:
Q←{1≥≢⍵:⍵ ⋄ s←⍵ ⍺⍺ ⍵⌷⍨?≢⍵ ⋄ (∇ ⍵⌿⍨0>s)⍪(⍵⌿⍨0=s)⍪(∇ ⍵⌿⍨0<s)}
……
The above formulation is not new; see for example Figure 3.7 of the classic The Design and Analysis of Computer Algorithms [Aho et al. 1974]. However, unlike the pidgin ALGOL program in Figure 3.7,Q
is executable, and the partial order used in the sorting is an operand, the(×-)
andcmp¨
andcmp⍤1
in the examples above.
Monadic⍋
was originally defined only on numeric vectors, and was extended [Wooster 1980] to work on numeric arrays with higher rank. With that extension it has the distinction of being the first APL primitive function defined to work on major cells, before the term was invented or the importance of the concept realized. It was later extended to work on character arrays in Dyalog APL in 1982. More recently,⍋
was extended in J to work with a TAO (total array ordering) [Hui 1996] on a suggestion by Whitney. TAO was taken up by Dyalog APL in 2018 [Brudzewsky et al. 2018]. The TAO also extends the left domain of⍸
. (The expression above for getting grade from sort requires TAO.)
Generate the sorted matrix of all permutations of⍳⍵
[Hui 2016a, §19; McDonnell 2003; Hui 2015b]. …… perm⍵
obtains by indexing each row of the matrix⍒⍤1 ∘.=⍨ ⍳⍵
by0,1+perm ⍵-1
. …… Putting it all together:
perm ← {0=⍵:1 0⍴0 ⋄ ((!⍵),⍵)⍴(⊂0,1+∇ ¯1+⍵)⌷⍤1 ⍒⍤1 ∘.=⍨ ⍳⍵}
An example of John Conway’s Game of Life [Gardner 1970] is obligatory with this operator. life below is due to Jay Foad, translated from an algorithm in k by Whitney [Hui 2017c]. It applies the rules of the Game of Life to the universe to create the next generation.
life ← {3=s-⍵∧4=s←{+⌿,⍵}⌺3 3⊢⍵}
⊢ glider←5 5⍴0 0 1 0 0 1 0 1 0 0 0 1 1,12⍴0
……
{'.⍟'[⍵]}¨ (⍳8) {life⍣⍺⊢⍵}¨ ⊂glider
……
In life, the derived function{+⌿,⍵}⌺3 3
computes the sum of each3
-by-3
square, moving by1
in each dimension. The function{'.⍟'[⍵]}
produces a compact display for a Boolean array.
Key is a monadic operator. In the dyadic case of the derived function⍺ f⌸ ⍵
, major cells of⍺
specify keys for the corresponding major cells of⍵
, andf
is applied to each unique key in⍺
and the selection of cells in⍵
having that key. In the monadic case of the derived function,f⌸⍵ ↔ ⍵ f⌸ ⍳≢⍵
:f
is applied to each unique key in⍵
and the indices in⍵
of that key.
Key was defined and implemented in J in 1989 or 1990 [Hui 2007] and in Dyalog APL in 2015 [Dyalog 2015; Hui 2020b]. It is motivated by the “generalized beta” operation in The Connection Machine [Hillis 1985, §2.6], but generalizes the generalized beta by accepting arrays of any rank, not just vectors, and by permitting any function, not just reductions (folds). Key is also cognate with the GROUP BY statement in SQL. ……
The following snippet solves a “Programming Pearls” puzzle [Bentley 1983]: given a dictionary of English words, here represented as the character matrixa
, find all sets of anagrams. ……he algorithm works by sorting the rows individually (note the use of the rank operator⍤
(§3.1)), and these sorted rows are used as keys (“signatures” in the Programming Pearls description) to group the rows of the matrix. As the anagram example illustrates, other APL functions can be used to create the requisite keys.
Generate⍵
random numbers selected from⍳≢⍺
according to the weights⍺
, a vector of positive real numbers [Hui 2017d]. For example, ifa←7 5 6 4 7 2 0.4
are the weights, then ina ran 1e6
the number0
should occur roughly as often as4
(both with a weight of7
) and3.5
times as often as5
(with a weight of2
).
ran ← {(0⍪+⍀⍺÷+⌿⍺)⍸?⍵⍴0}
……
The technique can be used to generate random numbers according to a probability distribution [Abramowitz and Stegun 1964, §26.8]. If a discrete distribution with valuesv
and probabilitiesp
, thenv[p ran ⍵]
. If a continuous distribution, convert it into a discrete one by dividing(¯∞,∞)
into an appropriate number of intervals. The interval midpoints are the values; the probabilities are the differences of the cumulative distribution function at the interval end points.
The problem was solved in 1975 [IPSA 1975]; the current solution uses to advantage the extension of?0
to generate a random number drawn uniformly from the open interval(0, 1)
(suggested by Whitney) and the interval index function⍸
(§2.3).
The following is an example of interval index⍸
(§2.3) and⌸
working together to illustrate the central limit theorem, that the sum of independent random variables converges to the normal distribution [Hui and Iverson 2004; Hui 2016b, §F].
t←¯1+{≢⍵}⌸(⍳51),(4×⍳50)⍸+⌿?10 1e6⍴21
……t
counts the number of occurrences for interval endpoints4×⍳50
, of1e6
samples from the sum of ten repetitions of uniform random selection of the integers from0
to20
. A barchart oft
:
.⎕'[(6e3×⊖⍳⌈(⌈/t)÷6e3)∘.≤t]
……
The derived function{≢⍵}⌸x
counts the number of occurrences of each unique cell ofx
. The Dyalog APL and J implementations recognize particular useful operands for key, for example{≢⍵}
and{f⌿⍵}
, and implement those cases with special code (§9.3) for better performance.
For vectorsR
andX
, the decode(or base-value) functionR⊥X
yields the value of the vector X evaluated in number system with radicesR[1],R[2],...,R[⍴R]
. ……
Scalar(or one-element vector) arguments are extended to conform, as required. ……
the decode function is extended to arrays in the manner of the inner product: each of the radix vectors along the last axis of the first argument is applied to each of the vectors along the first axis of the second argument.
#.
并未继承IBM对APL解码函数⊥
的扩展规定,它可以实现为:
decode=: {{x #."(1 _) (0|: y)}}
APL functions apply to collections of individual items called arrays. Arrays range from scalars, which are dimensionless, to multi-dimensional arrays of arbitrary rank and size.
For example, the grade function⍋
is commonly used to produce indices needed to reorder a vector into ascending order (as inX[⍋X]
), but may also be used in the treatment of permutations as the inverse function, that is,⍋P
yields the permutations as the inverse toP
.
IfP
andQ
are vectors of the same shape, then the expression+/P×Q
has a variety of useful interpretations. ……
The inner product produces functions equivalent to expressions in this form; it is denoted by a dot and applies the two function surround it. ThusP+.×Q
is equivalent to+/P×Q
, andP×.⋆Q
is equivalent to×/P⋆Q
, and, in general,Pf.gQ
is equivalent tof/PgQ
, ifP
andQ
are vectors.
The inner product is extended to arrays other than vectors along certain fixed axes, namely the last axis of the first argument and the first axis of the last argument. the lengths of these axes must agree. the shape of the result is obtained by deleting these axes and chaining the remaining shape vectors together. ……
The inner productM+.×N
is commonly called the matrix product. ……
Either argument of the inner product may be a scalar or a one-element vectors; it is extended in the usual manner.
The outer product operator, denoted by by the symbols∘.
preceding the function symbol, applies to any dyadic primitive scalar function, so that the function is evaluated for each member of the left argument paired with each member of the right argument. ……
Such tables may be better understood if labelled in a way widely used in elementary arithmetic texts: values of the arguments are placed beside and above the table, and the function whose outer product is being computed is shown at the corner.
Case | ⍴R | Definition |
---|---|---|
R←1⍉V |
⍴V |
R←V
|
R←1 2⍉M |
⍴M |
R←M
|
R←2 1⍉M |
(⍴M)[2 1] |
R[I;J]←M[J;I]
|
R←1 1⍉M |
⌊/⍴M |
R[I]←M[I;I]
|
R←1 2 3⍉T |
⍴T |
R←T
|
R←1 3 2⍉T |
(⍴T)[1 3 2] |
R[I;J;K]←T[I;K,J]
|
R←2 3 1⍉T |
(⍴T)[3 1 2] |
R[I;J;K]←T[J;K;I]
|
R←3 1 2⍉T |
(⍴T)[2 3 1] |
R[I;J;K]←T[K;I;J]
|
R←1 1 2⍉T |
(⌊/(⍴T)[1 2]),(⍴T)[3] |
R[I;J]←T[I;I;J]
|
R←1 2 1⍉T |
(⌊/(⍴T)[1 3]),(⍴T)[2] |
R[I;J]←T[I;J;I]
|
R←2 1 1⍉T |
(⌊/(⍴T)[2 3]),(⍴T)[1] |
R[I;J]←T[J;I;I]
|
R←1 1 1⍉T |
⌊/⍴T |
R[I]←T[I;I;I]
|
Table 3.9: TRANSPOSITION |
IfP
is any permutation of the indices of the axes of an arrayA
, thenP⍉A
is an array similar toA
except that the axes are permuted: theI
th axis becomes theP[I]
th axis of the result. Hence, ifR←P⍉A
, then(⍴R)[P]
is equal to⍴A
. For example:
A←2 3 5 7⍴⍳210
⍴A
2 3 5 7
P←2 3 4 1
⍴P⍉A
7 2 3 5
……
The monadic transpose⍉A
reverses the order of the axes of its argument. Formally,⍉A
is equivalent to(⌽⍳⍴⍴A)⍉A
.
⍉
运算规定中,不将多个轴映射到结果中的一个轴的简单示例,所对应的J语言代码:
transpose=: {{(/: x) |: y}}
a=: >:i. 2 3 5 7
$ a
2 3 5 7
p=: 2 3 4 1
$ p transpose a
7 2 3 5
More generally,Q⍉A
is a valid expression ifQ
is any vector equal in length to the rank ofA
which is "complete" in the sense that if its items include any integerN
they also include all positive integers less thenN
. For example, if⍴⍴A
is3
, then1 1 2
and2 1 1
and1 1 1
are suitable values forQ
but1 3 1
is not. Just as for the caseP⍉A
whereP
is a permutation, theI
th axis becomes theQ[I]
th axis ofQ⍉A
. However, in this case two or more of the axes ofA
may map into a single axis of the result, thus producing a diagonal section ofA
as illustrated below:
……
B←3 5⍴⍳15
B
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
1 1⍉B
1 7 13
A Direct Function (dfn) is a new function definition style, which bridges the gap between named function expressions such as rank←⍴∘⍴
and APL’s traditional ‘header’ style definition.
Explicit entities can be defined using direct definition. The digraphs{{
and}}
are reserved for delimiters, and text found between{{ }}
is taken to define a verb/adverb/conjunction. The text may be multiple lines long and may contain other embedded definitions. The part of speech of the defined entity is inferred from the words in it.
Jay Foad offers another stencil life, translating an algorithm in k by Arthur Whitney:
life3 ← {3=s-⍵∧4=s←{+/,⍵}⌺3 3⊢⍵} ⍝ Jay Foad
……
The algorithm combines the life rules into a single expression, whereins←{+/,⍵}⌺3 3 ⊢⍵
(0) for0
-cellss
is the number of neighbors; and
(1) for1
-cellss
is the number of neighbors plus1
, and the plus1
only matters ifs
is4
.
Dyadic transpose, x⍉y
, is probably one of the last primitives to be mastered for an APLer, but is actually straightforward to describe.
This paper describes a version of APL based upon the dictionary, but significantly simplified and enhanced, and directly usable on any machine that provides ASCII characters. It also describes salient features of a C implementation that has been tested on several machines, and is available as freeware.
Roger and I then began a collaboration on the design and implementation of a dialect of APL (later named J by Roger), first deciding to roughly follow “A Dictionary of APL” and to impose no requirement of compatibility with any existing dialect. We were assisted by suggestions from many sources, particularly in the design of the spelling scheme (E.B. Iverson and A.T. Whitney) and in the treatment of cells, items, and formatting (A.T. Whitney, based on his work on SHARP/HP and on the dialect A reported at the APL89 conference in New York).
A dictionary should not be read as an introduction to a language, but should rather be consulted in conjunction with other material that uses the language in some context of interest to the reader. Even the general section on grammar, which may be intelligible even to the beginner, should perhaps be studied only after a certain amount of other exposure to the language.
On the other hand, a dictionary should not be used only to find the meanings of individual words, but should also be studied to gain an overall view of the language. In particular, the grammar may be profitably reviewed again and again in the light of increased knowledge of the language, and the study of groups of related verbs and adverbs can reveal important relationships otherwise easily overlooked.
Nuclear Axis Operators - The nuax operator (denoted by⍤
) applies to a function left argument and a variable right argument to specify the axes which define the nuclei to which the function is to apply. ……The coax operator⍥
is also provided; its argument specifies the axes complementary to the nuclear axes.
In conventional APL, the scalar functions (which apply to scalar elements and produce scalar results) extend to higher rank arrays according to simple general rules; no corresponding general rules exist for the remaining so-called mixed functions. ……
Function rank is the most important notion needed to provide a simple and systematic basis for the uniform treatment of all “mixed” or non-scalar functions. ……
Iff
has rankr
, thenf⍵
is determined by applyingf
to each of the “cells” of shape(-r)↑⍴⍵
, producing a common shapes
for each, and assembling the whole into a result of shape((-r)↓⍴⍵),s
. ……
If the functiong←f⍤r
is to be applied dyadically as well as monadically (the only cases addressed in the preceding sections), then it is necessary thatr
specify three independent ranks, the monadic, the left, and the right. The general argumentr
is therefore a three-element vector that specifies the ranks in the order just indicated. Moreover,r
is extended by reshape if necessary, so thatf⍤r ←→ f⍤(⌽3⍴⌽r)
.
In combinatory logic one of the most useful primitive combinators is designated byS
[Sch24]. Curry definesSfgx
in prefix notation to befx(gx)
[CuFeCr74]. In common mathematical infix notation this would be given by(x)f(g(x))
, which one can write in APL asxfgx
, and this is the hook form(fg)x
. The combinatory logician appreciates this form because of its great expressiveness: it can be shown thatS
, along withK
, the constancy combinator, suffice to define all other combinators of interest [Ro50]. (The constancy combinatorK
is defined in infix notation so thatcKx
has the valuec
for allx
.) Users of APL will appreciate the hook for the same reasons.
Curry [Cu31] defines a formalizing combinator,Φ
, in prefix notation, such thatΦfghx
meansf(gx)(hx)
. In common mathematical infix notation this would be designated by(g(x))f(h(x))
. An example of this form isΦ+sin2cos2θ
, meaningsin2θ+cos2θ
. The fork(f g h)⍵
has the same meaning, namely(f⍵)g(h⍵)
. Curry named this the formalizing combinator because of its role in defining formal implication in terms of ordinary implication.
Iverson and Whitney have made several earlier suggestions of ways to achieve what the fork form provides: the scalar operators of [Iv78], [Iv79a], [Iv 79b], the til operator of [Iv82], the union and intersection conjunctions of [Iv87], and the yoke adverb of [Iv88]. Benkard [Bk87] has also suggested a way to achieve the meaning of this form, in his proposal for↑g/(f h)⍺ ⍵
, using the notion of function pair (↑
is APL2’s first function). The present proposal has significant advantages over these earlier ones.
To appreciate the more general use of tacit definition, it is necessary to understand three key notions of J: cells and rank, forks, and composition.……
The conjunction&
is called with, and applies to nouns (variables)a
andb
as well as to verbsf
andg
as follows:
a&g y
isa g y
f&b y
isx f y
f&g y
isf g y
x f&g y
is(g x) f (g y)
……
A number of other constructs in J similarly enhance the utility of tacit definitions. The more important are the under (or dual), atop (a second form of composition), the power conjunction^:
, and further forms of partitions.
@.
agenda@:
at&:
appose
Gerunds, verbal forms that can be used as nouns, are recognized as having utility in the realm of programming languages. We show that gerunds can be viewed as arrays of atomic repmentations of verbs (functions), in a way which is consistent with the syntax and semantics of APL, and which allows verbs to be first class objects in the language. We define derivations of verbs from gerunds in the J dialect of APL, and show how these derivations provide control structures for sequencing, selection (in the sense of generalized forms of CASE or SWITCH statements and IF/THEN/ELSE), iteration (DO UNTIL), recursion, and parallel computation (MIMD, or Multiple Instruction, Multiple Data). We conclude with alternative representations of verbs which are useful in other contexts.
`:1
replaced byu^:v
`:4
replaced bym~
`:5
replaced by@.
The enclose function as defined in [Operators and Enclosed Arrays] has made it possible to produce by straightforward APL functions the “index lists” required in indexing expressions of the forma[i;j]
, and therefore makes it possible to define a corresponding indexing function, which will be denoted by{
and called from:
i{a ←→ a[>i[0];>i[1]; ...]
Since the disclose function>
is permissive, the selection of any single element of a can be written without enclosures as, for example,1 2 3{a3
. Moreover, the left rank of{
is1
and its right rank is infinite, so that …… a simple left argumenti
of rank greater than1
produces an array of shape¯1↓⍴i
of elements chosen by the index vectors along its last axis, yielding what is sometimes called “scattered” indexing. For examp1e:
(3 2⍴⍳6){a2 ←→ a2[0;1],a2[2;3],a2[4;5]
……
In forming the left arguments of the indexing function, it will often be convenient to use the link function⊃
defined as follows:
⊃b ←→ <b
ifb
is simple
b
ifb
is non-simple
a⊃b ←→ (<a),⊃b
For example,(2 3⊃4⊃∘⊃5 6){a4 ←→ a[2 3;4;;5 6]
.
The indexing function{
as defined thus far provides all of the facilities provided by conventional indexing, and “scattered” and “complementary” indexing as well. Its power is further enhanced by allowing negative indexing …….
Dyadic{
encompasses all computations expressible by[;]
indexing of APL\360, as well as the new negative indexing and complementary indexing.
We also introduce a form of indexing called from denoted by⌷
, ……. The basic definition is:
i⌷a ↔ (,a)[⍉(⍴a)⊥⍉i]
The function⌷
distributes over any scalar function; thus,i⌷a+b ↔ (i⌷a)+(i⌷b)
. …… For example:
m←3 4⍴⍳12
m
0 1 2 3
4 5 6 7
8 9 10 11
2 2 ⌷ m
10
……
(3 2⍴3|⍳6)⌷m
1 8 6
⌷
(from)之时,解码前后不需要专门进行一元转置⍉
运算:
from=: {{(($ y) #. x) {::"(0 _) (, y)}}
]m=: 3 4$i.12
0 1 2 3
4 5 6 7
8 9 10 11
2 2 from m
10
3 2$3|i.6
0 1
2 0
1 2
(3 2$3|i.6)from m
1 8 6
The enclose function (denoted by<
) produces a scalar representation of its argument in the sense that the result is of rank zero, and that there exists an inverse function (called disclose, and denoted by>
) such thata ↔ ><a
for alla
. Any result producible by an expression which does not employ the enclose function is called a simple array, or is said to be simple.
Selection and reshaping functions apply without change to non-simple arrays. However, non-simple arrays are outside the domain of all other functions except for enclose, disclose, and equality (together with those functions such as≠
and∊
which are defined in terms of equality).
The equality function is extended to non-simple scalar arguments as follows:
1.(<a)≠a
for alla
2. Ifa
equalsb
(in rank, shape, and all elements), then(<a)=(<b)
yields1
……
The disclose function is scalar in the sense that it applies to each element of its argument, the new axes disclosed becoming the final axes of the result. ……
The disclose function applied to a simple arraya
produces a result identical toa
. Thus(<a)=<>a
is a test for whethera
is simple.
APL2 provides two significant facilities which apply at “depth” in the enclosure structure of an argument, the dyadic pick function, and the pervasive functions. RS provides no primitive corresponding to pick; it could be defined recursively by:
pick←''∇('→2+0=⍴⍺'⊃'(>0{⍺){(1↓⍺)∆⍵'⊃'⍵')
……
Since pervasiveness is a property assigned to functions, it would, in the framework of RS, be provided by an operator. Such an operator could be applied to any function (defined or derived as well as primitive) and, if defined to be dyadic, could provide greater variety. ……
If each essential space in an expression is counted as a character, then the link function and strand notation used to form non-simple vectors from simple vectors require expressions of nearly identical length. ……
RS does not include the heterogeneous arrays of APL2, and the production of equivalent constructs requires greater use of enclosure. However, the structure of RS does not preclude their introduction. ……
The monadic enclose functions defined in RS (<
) and in APL2 (⊂
) differ in one respect: ifs
is a simple scalar, thens≡⊂s
, but~s≡<s
. Although<
can therefore produce some structures not producible by⊂
, the differences between them (in the contexts of the respective systems) cannot, in most cases, be discerned.
Some verbsv
signal domain error on some extended arguments because the result is not integral; however,<.@v
and>.@v
are closed on extended arguments.
The operator denoted by the dot has been extended to provide a monadic function (as in-.×m
) as well as the established dyadic inner product function (as inn+.×m
). ……
The determinant of a square matrixm
is defined as the alternating sum (i.e. reduction by-
) of the!n←1↑⍴m
products overn
elements chosen (in each of the!n
possible ways) one from each row and column. Analogous calculations in which other function pairs are substituted for-
and×
lead to other useful functions; examples include the pairs⌈⌊
,∧∨
, and+×
, the last (called the permanent) being useful in combinatorics.
The case3⍤v
also has left rank2
, and⍺3⍤v⍵
appliesv
to each element produced by a tessellation of⍵
, using a size1{⍺
, and beginning points that are multiples of the “shift”0{⍺
.
The dual operator, denoted by⍢
, is a slight extension of the notion of dual functions implicit in deMorgan’s law (∨⍢~ ↔ ^
and≠⍢~ ↔ =
), the extension being to include a monadic left argument, as in⌊⍢-x ↔ ⌈x
. ……
Composition and the dual operator applied to a divalent left argument and a monadic (or divalent) right argument yield parallel definitions of divalent derived functions as follows:
……
Dual:f⍢g y ↔ (g⍣¯1) f (g y)
x f⍢g y ↔ (g⍣¯1) (g x) f (g y)
It should be noted that the extension of the dual to include the monadic definition makes the identities⌈⍢- ↔ ⌊
and⌊⍢- ↔ ⌈
hold for both the monadic case (floor and ceiling) and for the dyadic case (minimum and maximum). Moreover, for the dyadic case the exponential function yields the identities×⍢* ↔ +
and+⍢⍟ ↔ ×
, the latter of which provides the basis for the use of natural logarithms in multiplication, just as the identity+⍢(10¨⍟) ↔ x
forms the basis for the use of base ten logarithms.
The expressionf⍢>
produces a derived function which applies the functionf
to its argument in an “item-wise” fashion, by disclosing each element of the argument, applyingf
, and enclosing the result to produce the corresponding element of the overall result.
u⍥v
Rank: mv lv rv Upon; Upon
The monadu
is applied to the result ofv
, that is:
u⍥v ⍵ ←→ u v ⍵ ←→ u⍤v ⍵
⍺ u⍥v ⍵ ←→ u ⍺ v ⍵
u⍤v
Rank: mv mv mv On; On
Monad. In the simplest caseu⍤v ⍵
is equivalent tou v ⍵
. …… more generally, the rank of the derived functionu⍤v
is the rank ofv
; that is, the expressionu v
is applied to each of the cells of⍵
relative tov
. ……
Dyad. The left and right ranks ofu⍤v
are both the monadic rank ofv
. Therefore⍺ u⍤v ⍵
is equivalent to(v⍺) u v ⍵
.
Withe (u⍩v
) is similar to (u⍤v
), but appliesv
only to the right argument:⍺ u⍩v ⍵ ←→ ⍺ u v ⍵
u⍩v ⍵ ←→ ⍵ u v ⍵
u¨v
Rank: mv mv mv Under; Under
This function is equivalent to composition (u⍤v
) except that the function inverse tov
is applied to the result of each cell. …… The functionu¨v
is often called “the dual ofu
with respect tov
”, but the phrase “u
underv
” is probably better, suggesting thatu
is performed after preparatory work byv
, and before the task is sewn up by reversing the effect ofv
. The expressionu¨v
is valid only ifv
possesses an inverse.
The power operator, denoted by⍣
, applies to a monadic function left argumentf
and an integer right argumentk
to produce thek
th power off
in the following sense:f⍣k ↔ f f⍣k-1
, andf⍣1 ↔ f
. In particular,f⍣0
is the identity function andf⍣¯1
is the inverse off
. Moreover,f⍣_
denotes the limit off
, that is, the limiting functionf⍣n
forn
large. Similarly,f⍣¯
denotes the limit of the inverse off
.
This paper proposes two related extensions to APL: the extension of assignment to allow a nameF
to be assigned to a derived function by an expression of the formF←+.x
, and the introduction of a dyadic operator∇
to apply to character arraysD
andM
so thatD∇M
produces an ambivalent function in which the dyadic case is defined byD
and the monadic case byM
.
The proposed replacement for⎕fx
is a modification of the direct definition operator∇
defined in [A Function Definition Operator], ……
A function produced by the operator∇
may be assigned a name (as inf←m∇d
or ina(f←m∇d)b
), but it may also be used without assigning a name, as iny←''∇'⍺+÷⍵'/x
.
The use of the indexing function will be illustrated in a proof of the useful identityi⍉j⍉a ↔ i[j]⍉a
. We first state the definition of the transpose as follows: ifk
is any vector index ofj⍉a
then
k⌷j⍉a ↔ k[j]⌷a
Then:
k⌷i⍉j⍉a
k[i]⌷j⍉a
(k[i])[j]⌷a
k[i[j]]⌷a
k⌷i[j]⍉a
(<k){j|:a
↔ (<(/:j){k){a
,而恒等式i|:j|:a
↔ (i{j)|:a
的推导过程相应如下: (<k){i|:j|:a
(<(/:i){k){j|:a
(<(/:j){(/:i){k){a
(<k){(/:(/:j){(/:i))|:a
(<k){(i{j)|:a
A Direct Function (dfn) is a new function definition style, which bridges the gap between named function expressions such as rank←⍴∘⍴
and APL’s traditional ‘header’ style definition.
Explicit entities can be defined using direct definition. The digraphs{{
and}}
are reserved for delimiters, and text found between{{ }}
is taken to define a verb/adverb/conjunction. The text may be multiple lines long and may contain other embedded definitions. The part of speech of the defined entity is inferred from the words in it.
Ken and I had in mind to implement A Dictionary of APL [8] together with hooks and forks (phrasal forms) [20]. ……
The choice to implement forks was fortuitous and fortunate. We realized only later [32] that forks made tacit expressions (operator expressions) complete in the following sense: any sentence involving one or two arguments that did not use its arguments as an argument to an operator, can be written tacitly with fork and@:
(compose) and[
(left) and]
(right) and constant functions. If@:
were replaced by the equivalent special fork[: f g
, then a sentence can be written as an unbroken train (sequence of forks). ……
Meanwhile, Ken was concerned about the usefulness of forks, and worked hard at finding examples of forks beyond those in Phrasal Forms [20]. After a while, it seemed that everything was a fork. The explanation lies in the proof of completeness for tacit definition [32]: if the root (last) function in a sentence is applied dyadically, then a fork is required to write the sentence tacitly.
APL2 is based on this writer' s PhD Thesis [Br1], the array theory of Trenchard More [Mo1] and most of all on APL1. ……
The arrays of APL2 are finite rectangular arrays which contain arrays as items. When the term array is used, it means this subset of all possible arrays.
The arrays of APL2 are the same as the arrays of Array Theory and in particular empty arrays have structure as defined by Array Theory [Mo1 etc.].
An array one of whose items is other than a single number or character (a simple scalar) is called a nested array. An array containing only numbers or containing only characters is called a homogeneous array. An array all of whose items are either single numbers or single characters is called a simple array. The arrays of APL1 are simple and homogeneous.
In some sense every array in APL2 is nested because it contains other arrays. The term is reserved for those which contain at least one item which is not a single number or character. Thus the universe of arrays is partitioned into two subsets: simple arrays and nested arrays. ……
A function is pervasive if pick distributes over it. ……
Since the pick function may select an item at an arbitrary depth in a nested array, it may select deep enough to access a simple scalar (because nested arrays have finite depth). Thus a pervasive function may be thought of as applying independently to each simple scalar in its argument(s). ……
In APL2 the scalar functions and only the scalar functions are pervasive.
This paper describes a version of APL based upon the dictionary, but significantly simplified and enhanced, and directly usable on any machine that provides ASCII characters. It also describes salient features of a C implementation that has been tested on several machines, and is available as freeware.
Roger and I then began a collaboration on the design and implementation of a dialect of APL (later named J by Roger), first deciding to roughly follow “A Dictionary of APL” and to impose no requirement of compatibility with any existing dialect. We were assisted by suggestions from many sources, particularly in the design of the spelling scheme (E.B. Iverson and A.T. Whitney) and in the treatment of cells, items, and formatting (A.T. Whitney, based on his work on SHARP/HP and on the dialect A reported at the APL89 conference in New York).
In 1989, Iverson, together with Roger Hui and with input from Arthur Whitney, produced J, with a goal of providing a “shareware” APL implementation for use in teaching. The special APL characters were abandoned because it was felt that they require technical solutions which at that time were still prohibitively expensive in an educational environment. ……
J was clearly a “rationalization” of SHARP APL. ……
ACM SIGAPL, the ACM Special Interest Group on APL, reinterpreted the “APL” in its name in early 2009 as Array Programming Languages, so that J, k, Nial, etc. would be included in its purview.
A dictionary should not be read as an introduction to a language, but should rather be consulted in conjunction with other material that uses the language in some context of interest to the reader. Even the general section on grammar, which may be intelligible even to the beginner, should perhaps be studied only after a certain amount of other exposure to the language.
On the other hand, a dictionary should not be used only to find the meanings of individual words, but should also be studied to gain an overall view of the language. In particular, the grammar may be profitably reviewed again and again in the light of increased knowledge of the language, and the study of groups of related verbs and adverbs can reveal important relationships otherwise easily overlooked.
Nuclear Axis Operators - The nuax operator (denoted by⍤
) applies to a function left argument and a variable right argument to specify the axes which define the nuclei to which the function is to apply. ……The coax operator⍥
is also provided; its argument specifies the axes complementary to the nuclear axes.
In conventional APL, the scalar functions (which apply to scalar elements and produce scalar results) extend to higher rank arrays according to simple general rules; no corresponding general rules exist for the remaining so-called mixed functions. ……
Function rank is the most important notion needed to provide a simple and systematic basis for the uniform treatment of all “mixed” or non-scalar functions. ……
Iff
has rankr
, thenf⍵
is determined by applyingf
to each of the “cells” of shape(-r)↑⍴⍵
, producing a common shapes
for each, and assembling the whole into a result of shape((-r)↓⍴⍵),s
. ……
If the functiong←f⍤r
is to be applied dyadically as well as monadically (the only cases addressed in the preceding sections), then it is necessary thatr
specify three independent ranks, the monadic, the left, and the right. The general argumentr
is therefore a three-element vector that specifies the ranks in the order just indicated. Moreover,r
is extended by reshape if necessary, so thatf⍤r ←→ f⍤(⌽3⍴⌽r)
.
In combinatory logic one of the most useful primitive combinators is designated byS
[Sch24]. Curry definesSfgx
in prefix notation to befx(gx)
[CuFeCr74]. In common mathematical infix notation this would be given by(x)f(g(x))
, which one can write in APL asxfgx
, and this is the hook form(fg)x
. The combinatory logician appreciates this form because of its great expressiveness: it can be shown thatS
, along withK
, the constancy combinator, suffice to define all other combinators of interest [Ro50]. (The constancy combinatorK
is defined in infix notation so thatcKx
has the valuec
for allx
.) Users of APL will appreciate the hook for the same reasons.
Curry [Cu31] defines a formalizing combinator,Φ
, in prefix notation, such thatΦfghx
meansf(gx)(hx)
. In common mathematical infix notation this would be designated by(g(x))f(h(x))
. An example of this form isΦ+sin2cos2θ
, meaningsin2θ+cos2θ
. The fork(f g h)⍵
has the same meaning, namely(f⍵)g(h⍵)
. Curry named this the formalizing combinator because of its role in defining formal implication in terms of ordinary implication.
Iverson and Whitney have made several earlier suggestions of ways to achieve what the fork form provides: the scalar operators of [Iv78], [Iv79a], [Iv 79b], the til operator of [Iv82], the union and intersection conjunctions of [Iv87], and the yoke adverb of [Iv88]. Benkard [Bk87] has also suggested a way to achieve the meaning of this form, in his proposal for↑g/(f h)⍺ ⍵
, using the notion of function pair (↑
is APL2’s first function). The present proposal has significant advantages over these earlier ones.
To appreciate the more general use of tacit definition, it is necessary to understand three key notions of J: cells and rank, forks, and composition.……
The conjunction&
is called with, and applies to nouns (variables)a
andb
as well as to verbsf
andg
as follows:
a&g y
isa g y
f&b y
isx f y
f&g y
isf g y
x f&g y
is(g x) f (g y)
……
A number of other constructs in J similarly enhance the utility of tacit definitions. The more important are the under (or dual), atop (a second form of composition), the power conjunction^:
, and further forms of partitions.
@.
agenda@:
at&:
appose
Gerunds, verbal forms that can be used as nouns, are recognized as having utility in the realm of programming languages. We show that gerunds can be viewed as arrays of atomic repmentations of verbs (functions), in a way which is consistent with the syntax and semantics of APL, and which allows verbs to be first class objects in the language. We define derivations of verbs from gerunds in the J dialect of APL, and show how these derivations provide control structures for sequencing, selection (in the sense of generalized forms of CASE or SWITCH statements and IF/THEN/ELSE), iteration (DO UNTIL), recursion, and parallel computation (MIMD, or Multiple Instruction, Multiple Data). We conclude with alternative representations of verbs which are useful in other contexts.
`:1
replaced byu^:v
`:4
replaced bym~
`:5
replaced by@.
For years, Iverson struggled to achieve in APL the effect off+g
andf×g
as they are written in calculus. …… Finally, trains AKA forks were invented [Iverson and McDonnell 1989]. ……
Moreover,(f … h p q r) ↔ (f … h (p q r))
, and an isolated sequence of two functions is also assigned a meaning (atop, described below), so that a train of any length, even or odd, is interpreted. ……
Subsequently, it was realized that trains greatly increase the possibilities for “tacit definition”, expressions consisting of compositions of functions which do not explicitly mention the arguments [Hui et al. 1991]. Trains are implemented in several dialects: J [Hui et al. 1991], NARS2000 [Smith 2020], NGN APL [Nickolov 2013], and Dyalog APL [Scholes 2013]. ……
The expressive completeness of trains depends on an atop composition of two functions …… Dyalog APL defines 2-trains as atop. That, together with the functions⊣
(left) and⊢
(right), allows many common compositions to be written as trains.
For vectorsR
andX
, the decode(or base-value) functionR⊥X
yields the value of the vector X evaluated in number system with radicesR[1],R[2],...,R[⍴R]
. ……
Scalar(or one-element vector) arguments are extended to conform, as required. ……
the decode function is extended to arrays in the manner of the inner product: each of the radix vectors along the last axis of the first argument is applied to each of the vectors along the first axis of the second argument.
#.
并未继承IBM对APL解码函数⊥
的扩展规定,它可以实现为:
decode=: {{x #."(1 _) (0|: y)}}
We also introduce a form of indexing called from denoted by⌷
, ……. The basic definition is:
i⌷a ↔ (,a)[⍉(⍴a)⊥⍉i]
The function⌷
distributes over any scalar function; thus,i⌷a+b ↔ (i⌷a)+(i⌷b)
. …… For example:
m←3 4⍴⍳12
m
0 1 2 3
4 5 6 7
8 9 10 11
2 2 ⌷ m
10
……
(3 2⍴3|⍳6)⌷m
1 8 6
⌷
(from)之时,解码前后不需要专门进行一元转置⍉
运算:
from=: {{(($ y) #. x) {::"(0 _) (, y)}}
]m=: 3 4$i.12
0 1 2 3
4 5 6 7
8 9 10 11
2 2 from m
10
3 2$3|i.6
0 1
2 0
1 2
(3 2$3|i.6)from m
1 8 6
APL functions apply to collections of individual items called arrays. Arrays range from scalars, which are dimensionless, to multi-dimensional arrays of arbitrary rank and size.
The data structures of APL are rectangular, multi-dimensional, and flat -- the latter term meaning that all items of arrays are simple scalars. ……
In general, a system with nested arrays extends the power of APL by being able to represent data of non-zero depth. Also, in keeping with the past, the system includes a set of primitive functions and operators, tailor-made for manipulating these new data structures.
Continuing the above example, the names of the months of the year are best represented in a 12-item vector whose items are each character vectors. This structure has a depth of one. Note that because the individual names are in separate items, we need no longer resort to artifices like pad characters. Moreover, explicit delimiters are not needed as the separation between items is represented through structure rather than data. This particular representation is called a vector of vectors, and can be created as follows:
MONTHS ← ('JANUARY') ('FEBRUARY') ...
The above line also illustrates strand notation, used to enter a nested vector in a simple and convenient manner. ……
Of the several new operators, the only one specific to nested arrays is the each operator(symbol¨
), which is monadic as an operator, and produces an ambivalent derived function. It is used to apply the f unction which is its argument to the items of an array to produce corresponding items in the result. For example, to determine the length of the names of the months in the above example, use
⍴¨MONTHS
(7) (8) (5) (5) (3) (4) (4) (6) (9) (7) (8) (8)
Since monadic rho returns a vector , each item of the above result is a vector (specifically in these cases a one-item vector). The parentheses in the display indicate that the item is not a simple scalar.
APL2 is based on this writer' s PhD Thesis [Br1], the array theory of Trenchard More [Mo1] and most of all on APL1. ……
The arrays of APL2 are finite rectangular arrays which contain arrays as items. When the term array is used, it means this subset of all possible arrays.
The arrays of APL2 are the same as the arrays of Array Theory and in particular empty arrays have structure as defined by Array Theory [Mo1 etc.].
An array one of whose items is other than a single number or character (a simple scalar) is called a nested array. An array containing only numbers or containing only characters is called a homogeneous array. An array all of whose items are either single numbers or single characters is called a simple array. The arrays of APL1 are simple and homogeneous.
In some sense every array in APL2 is nested because it contains other arrays. The term is reserved for those which contain at least one item which is not a single number or character. Thus the universe of arrays is partitioned into two subsets: simple arrays and nested arrays. ……
A function is pervasive if pick distributes over it. ……
Since the pick function may select an item at an arbitrary depth in a nested array, it may select deep enough to access a simple scalar (because nested arrays have finite depth). Thus a pervasive function may be thought of as applying independently to each simple scalar in its argument(s). ……
In APL2 the scalar functions and only the scalar functions are pervasive.
The enclose function (denoted by<
) produces a scalar representation of its argument in the sense that the result is of rank zero, and that there exists an inverse function (called disclose, and denoted by>
) such thata ↔ ><a
for alla
. Any result producible by an expression which does not employ the enclose function is called a simple array, or is said to be simple.
Selection and reshaping functions apply without change to non-simple arrays. However, non-simple arrays are outside the domain of all other functions except for enclose, disclose, and equality (together with those functions such as≠
and∊
which are defined in terms of equality).
The equality function is extended to non-simple scalar arguments as follows:
1.(<a)≠a
for alla
2. Ifa
equalsb
(in rank, shape, and all elements), then(<a)=(<b)
yields1
……
The disclose function is scalar in the sense that it applies to each element of its argument, the new axes disclosed becoming the final axes of the result. ……
The disclose function applied to a simple arraya
produces a result identical toa
. Thus(<a)=<>a
is a test for whethera
is simple.
In order to provide users with access to APIs and frameworks, APL language designers searched for ways to integrate into APL, where everything is an array, selected aspects of the OO paradigm, where everything is an object. ……
Some interpreters, like APL+Win, avoided incorporating objects into the APL heap (or “workspace”). ……
Other systems added features which allowed variables, functions and operators to be organized in dynamic objects in the workspace. The resulting containers are known as namespaces (Dyalog APL) and locales (J). k implements dictionaries, which are also containers for arrays, but are typically used to contain arrays representing the columns of a relational table. …… The same language features which supported namespaces or classes within APL were used to wrap the external objects used by object oriented APIs, or platforms like the Microsoft’s OLE and .NET frameworks.
The choice of syntax for referring to a membername
of an objectemp
was not straightforward. ……
Most APL systems did adopt the notation from other OO languages — with a few exceptions.
emp.name
in most APL systems
name__emp
in J (retaining right-to-left evaluation)
emp[`name]
in k (using a symbol within index brackets to select from a dictionary)
……
Although APL interpreters have had extensive support for object oriented programming for nearly two decades, most APL users still feel that object and array paradigms are an awkward fit. …… Many of the benefits of OO are related to taking advantage of types, while much of the strength of the APL family is that you can write code which is shape, rank, and type agnostic — achieving many of the same goals as OO through radically different mechanisms.
For example, the grade function⍋
is commonly used to produce indices needed to reorder a vector into ascending order (as inX[⍋X]
), but may also be used in the treatment of permutations as the inverse function, that is,⍋P
yields the permutations as the inverse toP
.
Some verbsv
signal domain error on some extended arguments because the result is not integral; however,<.@v
and>.@v
are closed on extended arguments.
IfP
andQ
are vectors of the same shape, then the expression+/P×Q
has a variety of useful interpretations. ……
The inner product produces functions equivalent to expressions in this form; it is denoted by a dot and applies the two function surround it. ThusP+.×Q
is equivalent to+/P×Q
, andP×.⋆Q
is equivalent to×/P⋆Q
, and, in general,Pf.gQ
is equivalent tof/PgQ
, ifP
andQ
are vectors.
The inner product is extended to arrays other than vectors along certain fixed axes, namely the last axis of the first argument and the first axis of the last argument. the lengths of these axes must agree. the shape of the result is obtained by deleting these axes and chaining the remaining shape vectors together. ……
The inner productM+.×N
is commonly called the matrix product. ……
Either argument of the inner product may be a scalar or a one-element vectors; it is extended in the usual manner.
The outer product operator, denoted by by the symbols∘.
preceding the function symbol, applies to any dyadic primitive scalar function, so that the function is evaluated for each member of the left argument paired with each member of the right argument. ……
Such tables may be better understood if labelled in a way widely used in elementary arithmetic texts: values of the arguments are placed beside and above the table, and the function whose outer product is being computed is shown at the corner.
In the dyadic case, two frameslf
andrf
are involved, from the left and right arguments. Several different treatments are possible:
• scalar agreement:(lf≡rf)∨(lf≡⍬)∨(rf≡⍬)
, the left and right frames match, or one is the empty vector (⍬
). If the frames match, there are an equal number of left and right cells, and the operand function applies to corresponding cells. If they do not match, one frame must be⍬
, that is, there is one cell on one side, whence that one cell is applied against every cell on the other side. Scalar agreement is implemented in Dyalog APL [Dyalog 2015].
• prefix agreement:(p↑lf)≡(p↑rf) ⊣ p←(≢lf)⌊(≢rf)
, one frame must be a prefix of the other. Letff
be the longer frame (that is,ff←lf,p↓rf
). In this case a cell of the argument with the shorter frame is applied against×⌿p↓ff
cells of the other argument. Prefix agreement is implemented in J [Hui and Iverson 2004], and is consistent with the emphasis on the leading axis (§2).
• suffix agreement: one frame must be a suffix of the other. J had suffix agreement before it switched to prefix agreement in 1992 on a suggestion by Whitney [Whitney 1992].
• strict agreement: the frames must match. No dialect has ever implemented this.
The dual operator, denoted by⍢
, is a slight extension of the notion of dual functions implicit in deMorgan’s law (∨⍢~ ↔ ^
and≠⍢~ ↔ =
), the extension being to include a monadic left argument, as in⌊⍢-x ↔ ⌈x
. ……
Composition and the dual operator applied to a divalent left argument and a monadic (or divalent) right argument yield parallel definitions of divalent derived functions as follows:
……
Dual:f⍢g y ↔ (g⍣¯1) f (g y)
x f⍢g y ↔ (g⍣¯1) (g x) f (g y)
It should be noted that the extension of the dual to include the monadic definition makes the identities⌈⍢- ↔ ⌊
and⌊⍢- ↔ ⌈
hold for both the monadic case (floor and ceiling) and for the dyadic case (minimum and maximum). Moreover, for the dyadic case the exponential function yields the identities×⍢* ↔ +
and+⍢⍟ ↔ ×
, the latter of which provides the basis for the use of natural logarithms in multiplication, just as the identity+⍢(10¨⍟) ↔ x
forms the basis for the use of base ten logarithms.
The expressionf⍢>
produces a derived function which applies the functionf
to its argument in an “item-wise” fashion, by disclosing each element of the argument, applyingf
, and enclosing the result to produce the corresponding element of the overall result.
Ken and I had in mind to implement A Dictionary of APL [8] together with hooks and forks (phrasal forms) [20]. ……
The choice to implement forks was fortuitous and fortunate. We realized only later [32] that forks made tacit expressions (operator expressions) complete in the following sense: any sentence involving one or two arguments that did not use its arguments as an argument to an operator, can be written tacitly with fork and@:
(compose) and[
(left) and]
(right) and constant functions. If@:
were replaced by the equivalent special fork[: f g
, then a sentence can be written as an unbroken train (sequence of forks). ……
Meanwhile, Ken was concerned about the usefulness of forks, and worked hard at finding examples of forks beyond those in Phrasal Forms [20]. After a while, it seemed that everything was a fork. The explanation lies in the proof of completeness for tacit definition [32]: if the root (last) function in a sentence is applied dyadically, then a fork is required to write the sentence tacitly.
u⍥v
Rank: mv lv rv Upon; Upon
The monadu
is applied to the result ofv
, that is:
u⍥v ⍵ ←→ u v ⍵ ←→ u⍤v ⍵
⍺ u⍥v ⍵ ←→ u ⍺ v ⍵
u⍤v
Rank: mv mv mv On; On
Monad. In the simplest caseu⍤v ⍵
is equivalent tou v ⍵
. …… more generally, the rank of the derived functionu⍤v
is the rank ofv
; that is, the expressionu v
is applied to each of the cells of⍵
relative tov
. ……
Dyad. The left and right ranks ofu⍤v
are both the monadic rank ofv
. Therefore⍺ u⍤v ⍵
is equivalent to(v⍺) u v ⍵
.
Withe (u⍩v
) is similar to (u⍤v
), but appliesv
only to the right argument:⍺ u⍩v ⍵ ←→ ⍺ u v ⍵
u⍩v ⍵ ←→ ⍵ u v ⍵
u¨v
Rank: mv mv mv Under; Under
This function is equivalent to composition (u⍤v
) except that the function inverse tov
is applied to the result of each cell. …… The functionu¨v
is often called “the dual ofu
with respect tov
”, but the phrase “u
underv
” is probably better, suggesting thatu
is performed after preparatory work byv
, and before the task is sewn up by reversing the effect ofv
. The expressionu¨v
is valid only ifv
possesses an inverse.
One of the HOPL IV badges has an APL expression on it:÷+/÷(e≠0)/e
, the reciprocal of the sum of the reciprocals of the non-zero values ofe
. The expression computes the total resistance of components connected in parallel, whose resistance values are the vectore
.
There is an alternative phrasing in modern APL:+⌿⍢÷e~0
, sum under reciprocal (§3.5), without0
s. If arithmetic were extended to infinity (§4.6), in particular if÷0 ↔ ∞
and÷∞ ↔ 0
, then the expression would simplify to+⌿⍢÷e
, without the without0
(~0
).
The power operator, denoted by⍣
, applies to a monadic function left argumentf
and an integer right argumentk
to produce thek
th power off
in the following sense:f⍣k ↔ f f⍣k-1
, andf⍣1 ↔ f
. In particular,f⍣0
is the identity function andf⍣¯1
is the inverse off
. Moreover,f⍣_
denotes the limit off
, that is, the limiting functionf⍣n
forn
large. Similarly,f⍣¯
denotes the limit of the inverse off
.
This paper proposes two related extensions to APL: the extension of assignment to allow a nameF
to be assigned to a derived function by an expression of the formF←+.x
, and the introduction of a dyadic operator∇
to apply to character arraysD
andM
so thatD∇M
produces an ambivalent function in which the dyadic case is defined byD
and the monadic case byM
.
The proposed replacement for⎕fx
is a modification of the direct definition operator∇
defined in [A Function Definition Operator], ……
A function produced by the operator∇
may be assigned a name (as inf←m∇d
or ina(f←m∇d)b
), but it may also be used without assigning a name, as iny←''∇'⍺+÷⍵'/x
.
A Direct Function (dfn) is a new function definition style, which bridges the gap between named function expressions such as rank←⍴∘⍴
and APL’s traditional ‘header’ style definition.
Explicit entities can be defined using direct definition. The digraphs{{
and}}
are reserved for delimiters, and text found between{{ }}
is taken to define a verb/adverb/conjunction. The text may be multiple lines long and may contain other embedded definitions. The part of speech of the defined entity is inferred from the words in it.
Case | ⍴R | Definition |
---|---|---|
R←1⍉V |
⍴V |
R←V
|
R←1 2⍉M |
⍴M |
R←M
|
R←2 1⍉M |
(⍴M)[2 1] |
R[I;J]←M[J;I]
|
R←1 1⍉M |
⌊/⍴M |
R[I]←M[I;I]
|
R←1 2 3⍉T |
⍴T |
R←T
|
R←1 3 2⍉T |
(⍴T)[1 3 2] |
R[I;J;K]←T[I;K,J]
|
R←2 3 1⍉T |
(⍴T)[3 1 2] |
R[I;J;K]←T[J;K;I]
|
R←3 1 2⍉T |
(⍴T)[2 3 1] |
R[I;J;K]←T[K;I;J]
|
R←1 1 2⍉T |
(⌊/(⍴T)[1 2]),(⍴T)[3] |
R[I;J]←T[I;I;J]
|
R←1 2 1⍉T |
(⌊/(⍴T)[1 3]),(⍴T)[2] |
R[I;J]←T[I;J;I]
|
R←2 1 1⍉T |
(⌊/(⍴T)[2 3]),(⍴T)[1] |
R[I;J]←T[J;I;I]
|
R←1 1 1⍉T |
⌊/⍴T |
R[I]←T[I;I;I]
|
Table 3.9: TRANSPOSITION |
Dyadic transpose, x⍉y
, is probably one of the last primitives to be mastered for an APLer, but is actually straightforward to describe.
IfP
is any permutation of the indices of the axes of an arrayA
, thenP⍉A
is an array similar toA
except that the axes are permuted: theI
th axis becomes theP[I]
th axis of the result. Hence, ifR←P⍉A
, then(⍴R)[P]
is equal to⍴A
. For example:
A←2 3 5 7⍴⍳210
⍴A
2 3 5 7
P←2 3 4 1
⍴P⍉A
7 2 3 5
……
The monadic transpose⍉A
reverses the order of the axes of its argument. Formally,⍉A
is equivalent to(⌽⍳⍴⍴A)⍉A
.
⍉
运算规定中,不将多个轴映射到结果中的一个轴的简单示例,所对应的J语言代码:
transpose=: {{(/: x) |: y}}
a=: >:i. 2 3 5 7
$ a
2 3 5 7
p=: 2 3 4 1
$ p transpose a
7 2 3 5
The use of the indexing function will be illustrated in a proof of the useful identityi⍉j⍉a ↔ i[j]⍉a
. We first state the definition of the transpose as follows: ifk
is any vector index ofj⍉a
then
k⌷j⍉a ↔ k[j]⌷a
Then:
k⌷i⍉j⍉a
k[i]⌷j⍉a
(k[i])[j]⌷a
k[i[j]]⌷a
k⌷i[j]⍉a
(<k){j|:a
↔ (<(/:j){k){a
,而恒等式i|:j|:a
↔ (i{j)|:a
的推导过程相应如下: (<k){i|:j|:a
(<(/:i){k){j|:a
(<(/:j){(/:i){k){a
(<k){(/:(/:j){(/:i))|:a
(<k){(i{j)|:a
Well, we don’t know what Ken Iverson’s favorite APL expression was or if he even had a favorite APL expression. But we can guess. From A History of APL in 50 Functions [Hui 2016a, §8]:
⊢ x←,1
1
⊢ x←(0,x)+(x,0)
1 1
⊢ x←(0,x)+(x,0)
1 2 1
⊢ x←(0,x)+(x,0)
1 3 3 1
The expression(0,x)+(x,0)
or its commute, which generates the next set of binomial coefficients, …….
What is being indexed is an array (of course) but the indices themselves (the “subscripts”) can also be arrays. For example [Hui 2016a, §4]:
x← 3 1 4 1 5 9
'.⎕'[x∘.>⍳⌈⌿x]
……
In the example, the 2-element character vector'.⎕'
is indexed by a 6-by-9 Boolean matrix.
More generally,Q⍉A
is a valid expression ifQ
is any vector equal in length to the rank ofA
which is "complete" in the sense that if its items include any integerN
they also include all positive integers less thenN
. For example, if⍴⍴A
is3
, then1 1 2
and2 1 1
and1 1 1
are suitable values forQ
but1 3 1
is not. Just as for the caseP⍉A
whereP
is a permutation, theI
th axis becomes theQ[I]
th axis ofQ⍉A
. However, in this case two or more of the axes ofA
may map into a single axis of the result, thus producing a diagonal section ofA
as illustrated below:
……
B←3 5⍴⍳15
B
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
1 1⍉B
1 7 13
Monadic⍋
was originally defined only on numeric vectors, and was extended [Wooster 1980] to work on numeric arrays with higher rank. With that extension it has the distinction of being the first APL primitive function defined to work on major cells, before the term was invented or the importance of the concept realized. It was later extended to work on character arrays in Dyalog APL in 1982. More recently,⍋
was extended in J to work with a TAO (total array ordering) [Hui 1996] on a suggestion by Whitney. TAO was taken up by Dyalog APL in 2018 [Brudzewsky et al. 2018]. The TAO also extends the left domain of⍸
. (The expression above for getting grade from sort requires TAO.)
Key is a monadic operator. In the dyadic case of the derived function⍺ f⌸ ⍵
, major cells of⍺
specify keys for the corresponding major cells of⍵
, andf
is applied to each unique key in⍺
and the selection of cells in⍵
having that key. In the monadic case of the derived function,f⌸⍵ ↔ ⍵ f⌸ ⍳≢⍵
:f
is applied to each unique key in⍵
and the indices in⍵
of that key.
Key was defined and implemented in J in 1989 or 1990 [Hui 2007] and in Dyalog APL in 2015 [Dyalog 2015; Hui 2020b]. It is motivated by the “generalized beta” operation in The Connection Machine [Hillis 1985, §2.6], but generalizes the generalized beta by accepting arrays of any rank, not just vectors, and by permitting any function, not just reductions (folds). Key is also cognate with the GROUP BY statement in SQL. ……
The following snippet solves a “Programming Pearls” puzzle [Bentley 1983]: given a dictionary of English words, here represented as the character matrixa
, find all sets of anagrams. ……he algorithm works by sorting the rows individually (note the use of the rank operator⍤
(§3.1)), and these sorted rows are used as keys (“signatures” in the Programming Pearls description) to group the rows of the matrix. As the anagram example illustrates, other APL functions can be used to create the requisite keys.
This paper describes a version of APL based upon the dictionary, but significantly simplified and enhanced, and directly usable on any machine that provides ASCII characters. It also describes salient features of a C implementation that has been tested on several machines, and is available as freeware.
In combinatory logic one of the most useful primitive combinators is designated byS
[Sch24]. Curry definesSfgx
in prefix notation to befx(gx)
[CuFeCr74]. In common mathematical infix notation this would be given by(x)f(g(x))
, which one can write in APL asxfgx
, and this is the hook form(fg)x
. The combinatory logician appreciates this form because of its great expressiveness: it can be shown thatS
, along withK
, the constancy combinator, suffice to define all other combinators of interest [Ro50]. (The constancy combinatorK
is defined in infix notation so thatcKx
has the valuec
for allx
.) Users of APL will appreciate the hook for the same reasons.
Curry [Cu31] defines a formalizing combinator,Φ
, in prefix notation, such thatΦfghx
meansf(gx)(hx)
. In common mathematical infix notation this would be designated by(g(x))f(h(x))
. An example of this form isΦ+sin2cos2θ
, meaningsin2θ+cos2θ
. The fork(f g h)⍵
has the same meaning, namely(f⍵)g(h⍵)
. Curry named this the formalizing combinator because of its role in defining formal implication in terms of ordinary implication.
Iverson and Whitney have made several earlier suggestions of ways to achieve what the fork form provides: the scalar operators of [Iv78], [Iv79a], [Iv 79b], the til operator of [Iv82], the union and intersection conjunctions of [Iv87], and the yoke adverb of [Iv88]. Benkard [Bk87] has also suggested a way to achieve the meaning of this form, in his proposal for↑g/(f h)⍺ ⍵
, using the notion of function pair (↑
is APL2’s first function). The present proposal has significant advantages over these earlier ones.
To appreciate the more general use of tacit definition, it is necessary to understand three key notions of J: cells and rank, forks, and composition.……
The conjunction&
is called with, and applies to nouns (variables)a
andb
as well as to verbsf
andg
as follows:
a&g y
isa g y
f&b y
isx f y
f&g y
isf g y
x f&g y
is(g x) f (g y)
……
A number of other constructs in J similarly enhance the utility of tacit definitions. The more important are the under (or dual), atop (a second form of composition), the power conjunction^:
, and further forms of partitions.
@.
agenda@:
at&:
appose
Gerunds, verbal forms that can be used as nouns, are recognized as having utility in the realm of programming languages. We show that gerunds can be viewed as arrays of atomic repmentations of verbs (functions), in a way which is consistent with the syntax and semantics of APL, and which allows verbs to be first class objects in the language. We define derivations of verbs from gerunds in the J dialect of APL, and show how these derivations provide control structures for sequencing, selection (in the sense of generalized forms of CASE or SWITCH statements and IF/THEN/ELSE), iteration (DO UNTIL), recursion, and parallel computation (MIMD, or Multiple Instruction, Multiple Data). We conclude with alternative representations of verbs which are useful in other contexts.
`:1
replaced byu^:v
`:4
replaced bym~
`:5
replaced by@.
APL2 is based on this writer' s PhD Thesis [Br1], the array theory of Trenchard More [Mo1] and most of all on APL1. ……
The arrays of APL2 are finite rectangular arrays which contain arrays as items. When the term array is used, it means this subset of all possible arrays.
The arrays of APL2 are the same as the arrays of Array Theory and in particular empty arrays have structure as defined by Array Theory [Mo1 etc.].
An array one of whose items is other than a single number or character (a simple scalar) is called a nested array. An array containing only numbers or containing only characters is called a homogeneous array. An array all of whose items are either single numbers or single characters is called a simple array. The arrays of APL1 are simple and homogeneous.
In some sense every array in APL2 is nested because it contains other arrays. The term is reserved for those which contain at least one item which is not a single number or character. Thus the universe of arrays is partitioned into two subsets: simple arrays and nested arrays. ……
A function is pervasive if pick distributes over it. ……
Since the pick function may select an item at an arbitrary depth in a nested array, it may select deep enough to access a simple scalar (because nested arrays have finite depth). Thus a pervasive function may be thought of as applying independently to each simple scalar in its argument(s). ……
In APL2 the scalar functions and only the scalar functions are pervasive.
A Direct Function (dfn) is a new function definition style, which bridges the gap between named function expressions such as rank←⍴∘⍴
and APL’s traditional ‘header’ style definition.
Explicit entities can be defined using direct definition. The digraphs{{
and}}
are reserved for delimiters, and text found between{{ }}
is taken to define a verb/adverb/conjunction. The text may be multiple lines long and may contain other embedded definitions. The part of speech of the defined entity is inferred from the words in it.
Case | ⍴R | Definition |
---|---|---|
R←1⍉V |
⍴V |
R←V
|
R←1 2⍉M |
⍴M |
R←M
|
R←2 1⍉M |
(⍴M)[2 1] |
R[I;J]←M[J;I]
|
R←1 1⍉M |
⌊/⍴M |
R[I]←M[I;I]
|
R←1 2 3⍉T |
⍴T |
R←T
|
R←1 3 2⍉T |
(⍴T)[1 3 2] |
R[I;J;K]←T[I;K,J]
|
R←2 3 1⍉T |
(⍴T)[3 1 2] |
R[I;J;K]←T[J;K;I]
|
R←3 1 2⍉T |
(⍴T)[2 3 1] |
R[I;J;K]←T[K;I;J]
|
R←1 1 2⍉T |
(⌊/(⍴T)[1 2]),(⍴T)[3] |
R[I;J]←T[I;I;J]
|
R←1 2 1⍉T |
(⌊/(⍴T)[1 3]),(⍴T)[2] |
R[I;J]←T[I;J;I]
|
R←2 1 1⍉T |
(⌊/(⍴T)[2 3]),(⍴T)[1] |
R[I;J]←T[J;I;I]
|
R←1 1 1⍉T |
⌊/⍴T |
R[I]←T[I;I;I]
|
Table 3.9: TRANSPOSITION |