Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Not by me. Not by most people I reckon.

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.


I wonder if some of the popularity of "functional" in imperative languages is that it lets you put this sort of stuff together without needing an "array language". In python it's pretty easy to

    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.


It's worth noting that the behavior is totally different if you pass higher dimensional matrices. The Fortran, Python, Haskell, etc. code will all break or fail to typecheck, whereas the APL/J/K implicitly maps over them. Understanding this topic ("rank") is a major source of confusion for new users and power for existing users, as lots of different mapping regimes can be obtained without a lot of additional operators.

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.


The Python-with-NumPy example I gave at https://news.ycombinator.com/item?id=16849500 supports higher dimensional matrices:

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


Very cool, I did not know that! Thank you for posting this example!


It seems to me that mathematical higher dimensional matrices are, in the broad scheme of programming languages, a corner case. Certainly a big one and an important one, but not one that was ever likely to drive general purpose languages.

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.


I think it's kind of a chicken-and-egg question, personally. Compared to array languages, most other programming languages are, in a sense, tree-oriented. Does their prevalence mean that our problems are mostly tree-structured? Or is our propensity to see problems as tree-structured a result of brainwashing by our tools? "A prisoner falls in love with his chains" as Dijkstra said.


A "Python with Numpy" programmer who decides to not use the built-in factorial function would think:

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


R and Matlab are definitely array-oriented in that sense (though not fully). Here's how you might do it in R:

    prod(1:x)


Julia:

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.


It's just that the language ought not to offer other ways, and must be very terse? Otherwise it seems like many languages would qualify:

    julia> fact(n) = prod(1:n)
That's 9 characters, shorter than q. (`julia> const Π=prod` brings it to 6, only apl is shorter.)


But is that how most Julia programmers will write it?

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


Depends whether they cut their teeth on Matlab!

I'm not sure which is faster here, often writing out the loop is a little faster but less compact.


They're equally fast:

    julia> @btime fact_prod(10000)
    7.833 μs (0 allocations: 0 bytes)

    julia> @btime fact_loop(10000)
    7.908 μs (0 allocations: 0 bytes)


Here is a Fortran 95 program to compute the factorial of 0 through 5. The factorial can be computed as the product of an array created on the fly, without an explicit loop.

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


Sorry, I need to learn how to post code here.


    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


Put two spaces in front of the content you want to appear as a code block (two spaces in front of each line):

  this version respects
  line breaks while
this version does not respect line breaks.


I like that definition! Not least because it means Futhark qualifies as an array language: i32.product (map (1+) (iota n)). I have also heard the more fundamentalist definition that if you have to say 'map', then it is not an array language.




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: