Consider the lone factorial problem: Every array programmer will do some kind of the product of, one plus array of all ints up to x
apl: ×/⍳X
q: prd 1+til x
j: */1+i.x
k: */1+!x
Notice how similar they are?Now, how do you solve this problem in Fortran? In Python? In R? In Matlab? What's the first tool in your toolbox? Is it to iterate over the values?
FUNCTION FACT(N)
INTEGER N,I,FACT
FACT=1
DO 10 I=1,N
10 FACT=FACT*I
END
def fact(n):
result = 1
for i in range(1, n+1):
result *= i
return result
function b=fact(a)
b=1;
for i=1:a
b=b*i;
end
function fact = iter_fact(n)
fact = 1;
for i = 2:n
fact = fact * i;
endfor
endfunction
fact <- function(n) {
f = 1
for (i in 2:n) f <- f * i
f
}
If the native programmer's first impulse looks something like that, then it's not an array language because the programmer isn't thinking in terms of arrays.program xfact integer :: i print*,fact([(i,i=0,5)]) contains elemental function fact(n) integer, intent(in) :: n integer :: i,fact fact = product([(i,i=1,n)]) end function fact end program xfact
this version respects
line breaks while
this version does not
respect line breaks. program xfact
integer::i
print *, fact ([(i, i = 0, 5)])
contains
elemental function fact (n)
integer, intent (in)::n
integer::i
fact = product ([(i, i = 1, n)])
end function fact
end program xfact julia> fact(n) = prod(1:n)
That's 9 characters, shorter than q. (`julia> const Π=prod` brings it to 6, only apl is shorter.)I just asked someone in my office and they sent me this:
function fact(n::Integer)
n < 0 && return zero(n)
f = one(n)
for i in 2:n
f *= i
end
return f
end
They seem to have google'd the result, but I'm not judging that: That might be how Julia programmers code...I'm not sure which is faster here, often writing out the loop is a little faster but less compact.
julia> @btime fact_prod(10000)
7.833 μs (0 allocations: 0 bytes)
julia> @btime fact_loop(10000)
7.908 μs (0 allocations: 0 bytes) def product(iterable):
return reduce(operator.mul, iterable, 1)
>> prod(range(1, 5))
24
(albeit with some imports, and note range is [begin, end) so that's 4!, not 5!). It might not be the first thing a Python programmer does, but it's certainly reasonable. Haskell of course is Prelude> foldl (*) 1 [1..5]
120
(inclusive this time, hence 5!) which is only slightly more verbose than the "array" languages, but does have the advantage of clearly specifying what your base case is if the list is empty.Perhaps array languages are just getting subsumed as a special case of "functional programming", be it either the relatively weakly-guaranteed FP that gets embedded into otherwise OO/imperative languages or Haskell's stronger-guarentees FP.
The rank operator in J (and probably Dyalog APL) allows you to treat a 3D matrix as an array of 2D matrices, a 2D matrix of arrays, a single item or a bunch of unit-sized boxes. This concept generalizes to higher dimensions. I don't think this aspect of array programming has gotten as much airtime as it deserves, probably because it is complex, but this is where the semantics of array languages and conventional languages really differ.
Indeed, I'd argue that if that was your primary use case you are and always were better off with a relatively custom language (relative to programming as a whole), because the needs are so different and the wins so big using an environment set up to support those needs that you'll want that in the end. You can fuzz the line with things like NumPy, because all these lines are fuzzy, but dedicated support will be a big win in the end.
>>> import numpy as np
>>> np.multiply.reduce(np.array([[1,2,3,4], [5,6,7,8]]))
array([ 5, 12, 21, 32])
and it lets you reshape into different forms, like: >>> arr = np.array([[1,2,3,4], [5,6,7,8]])
>>> np.multiply.reduce(arr.flatten())
40320
>>> np.multiply.reduce(arr.reshape((4,2)))
array([105, 384])
>>> np.multiply.reduce(arr.reshape((2,2,2)))
array([[ 5, 12],
[21, 32]])
I believe this was influenced by the array languages. prod(1:x)fact(n::Integer) = prod(1:n)
But I wouldn't call Julia an array programming language. Not everything is an array, there are scalars too, and vectors (vs matrices) are very special arrays that exhibit the expected duality properites (since 0.6)
It's kind of crazy to think of Matlab as not an array programming language since the array is literally the only data type.
>>> from numpy import np
>>> np.multiply.reduce(np.arange(1, 10+1))
3628800
That same programmer would (hopefully) also be aware that the function will overflow for large-enough values, and might instead write it at: >>> np.multiply.reduce(np.arange(1, 1000+1, dtype=np.object))Fortran and Python are much more general purpose languages that also happen to have array operations to speed things up.
Matlab/Octave are more math oriented than any of the above and are far more than just programming languages, they are more like interactive notebooks, the IDE for Matlab (and for Octave too now, though I haven't worked much with it) is so closely coupled with the language that the language has no stand-alone right to existence.
APL, J and K are all more closely related to each other than to any of the others, the closest of the others would be R.
In J for example, you could factor your code out. The way you factor mathematics. Their power lies in their notation.
Outside of the notation, If you have a multidimensional array, you can operate on ranks of it. You can write loopless code, you don't need for, do, while loops. The compounding and combining of verbs allows for a very functional style of programming that you can never realize in the languages you mentioned. You have to understand APL was designed for describing algorithms before it got turned into a computer language.
No. Is like claim "C" is a OO language. Is more correct to say it have "array capabilities".
To be considered an "X" language it must that "X" be the most primitive/idiomatic/natural/default way to think and program on that. And also a primitive of the language!
You can do OO on SQL, but that is hardly the idea!
Similar, with a array language you see everything as arrays and as array manipulation and rarely deviate from that. This is the same on other languages.
Even in multi-paradigm languages like python or C# maybe you put a little functional here or linq there but that portion of the code seriously look "alien"
Mind you, I cut my teeth on R, so needing to use loops in other languages confused the hell out of me at first.