[HN Gopher] Array Languages: R vs. APL (2023)
       ___________________________________________________________________
        
       Array Languages: R vs. APL (2023)
        
       Author : todsacerdoti
       Score  : 76 points
       Date   : 2024-03-20 20:52 UTC (1 days ago)
        
 (HTM) web link (jcarroll.com.au)
 (TXT) w3m dump (jcarroll.com.au)
        
       | olliej wrote:
       | I personally think APL is wonderful simply because of the
       | original APL specific keyboard [1]
       | 
       | I've looked briefly at R and found the syntax and semantics to be
       | less than stellar. Obviously there's going to be some bias in
       | that sentiment due me not generally doing "array programming",
       | but I don't believe the things that irked me were entirely as a
       | result of that.
       | 
       | The more annoying stuff for R is entirely second hand. As far as
       | I can tell R (or at least R studio) maintains implicit state
       | between runs which means you can get to a position where the same
       | code works on some runs, and then not on later runs. My friend
       | was having to do a lot of bioinformatics processing (many of the
       | libraries for this are in R) and was constantly fighting to have
       | code she wrote to process the data or produce charts
       | (publications in bioinformatics have an acceptance bias for
       | "looks like it came from R" that is similar to what CS [used to?]
       | have for gnu plot). But you could run the same scripts on the
       | same input and have it fail where previously it worked. This is
       | before you deal with inter-version compatibility problems which
       | also seemed frequent.
       | 
       | What was irksome to me looking at a lot of the stuff that were
       | doing is that it was fundamentally mostly basic scripting stuff
       | you could do in other languages trivially (and more cleanly imo)
       | but there were a bunch of functions (builtin or from libraries?)
       | that did the work, but those functions weren't in R, so the
       | claims that R was "necessary" seemed fairly bogus to me.
       | 
       | [1]
       | https://en.wikipedia.org/wiki/APL_(programming_language)#/me...
        
         | crispyambulance wrote:
         | > [R/RStudio] maintains implicit state between runs...
         | 
         | That can be turned off and is, in fact, widely recommended to
         | not keep one's workspace between runs.                 > This
         | is before you deal with inter-version compatibility problems
         | which also seemed frequent.
         | 
         | Yeah, that can be a problem with libraries (as it is with
         | python dependencies). It really afflicts long-running projects.
         | R has taken a cue from the python world there. renv the best
         | way (IMHO) to maintain a reproduceable environment in R
         | (https://rstudio.github.io/renv/articles/renv.html).
         | 
         | R is nicely cogent in syntax and largely "just works" once you
         | accept its idiosyncrasies.
        
         | goosedragons wrote:
         | You can save your workspace (state) in R. It's generally bad
         | practice to do so.
         | 
         | R is VERY VERY good at handling tabular data. Python can get
         | kind of close with Pandas but IMO, it's still more awkward than
         | base R data frames and way worse than data.table.
         | 
         | R also has a lot of built-ins geared for statistics and built
         | by statisticians. If you're do it statistics there's value in
         | not having to find a library or libraries that do that.
        
         | rzmmm wrote:
         | R has a lot high quality packages which implement e.g.
         | frequently used sophisticated regression analysis algorithms.
         | Python has these too but in my experience they are not that
         | well tested and suffer from bugs.
        
       | weinzierl wrote:
       | > _" So, would APL be "readable" if I was more familiar with it?
       | Let's find out!"_
       | 
       | An alternative test for this hypothesis might have been using the
       | language J, which is an array language based on APL and by the
       | designer of APL but only using ASCII characters.
        
         | nonfamous wrote:
         | R itself could be considered a test of this hypothesis, too.
         | It's been said that elegant, powerful Lisp would be more widely
         | adopted if it wasn't for all those gosh-darned parenthesis.
         | 
         | Well, at its core R _is_ a Lisp (specifically, Scheme) but with
         | a more traditional syntax (infixed operators, function calls,
         | etc). And it's fair to say the adoption of R has, indeed, been
         | more widespread than that of Lisp.
        
           | anthk wrote:
           | J it's standalone, it doesn't use APL in the background.
        
           | mik1998 wrote:
           | I'm not sure I would come to this conclusion. R has some
           | adoption, but it's also really not used as a generic
           | programming language, which most Lisp dialects are.
        
         | pavon wrote:
         | J primitives are easier to type, but they aren't any more
         | readable or familiar to newcomers than APL symbols.
        
       | bnprks wrote:
       | One of the wildest R features I know of comes as a result of lazy
       | argument evaluation combined with the ability to programmatically
       | modify the set of variable bindings. This means that functions
       | can define local variables that are usable by their arguments
       | (i.e. `f(x+1)` can use a value of `x` that is provided from
       | within `f` when evaluating `x+1`). This is used extensively in
       | practice in the dplyr, ggplot, and other tidyverse libraries.
       | 
       | I think software engineers often get turned off by the weird
       | idiosyncrasies of R, but there are surprisingly unique (arguably
       | helpful) language features most people don't notice. Possibly
       | because most of the learning material is data-science focused and
       | so it doesn't emphasize the bonkers language features that R has.
        
         | VTimofeenko wrote:
         | Asking out of lack of experience with R: how does such
         | invocation handle case when `x` is defined with a different
         | value at call site?
         | 
         | In pseudocode:                 f =       let x = 1 in # inner
         | vars for f go here       arg -> arg + 1 # function logic goes
         | here            # example one: no external value       f (x+1)
         | # produces 3 (arg := (x+1) = 2; return arg +1)            #
         | example two: x is defined in the outer scope       let x = 4 in
         | f (x+2) # produces 5 (arg := 4; return arg + 1)? Or 3 if inner
         | x wins as in example one?
        
           | hugh-avherald wrote:
           | Well the point is that the function can define its own logic
           | to determine the behaviour. Users can also (with some limits)
           | restrict the variable scope.
        
           | bnprks wrote:
           | If the function chooses to overwrite the value of a variable
           | binding, it doesn't matter how it is defined at the call site
           | (so inner x wins in your example). In the tidyverse
           | libraries, they often populate a lazy list variable (think
           | python dictionary) that allows disambiguating in the case of
           | name conflicts between the call site and programmatic
           | bindings. But that's fully a library convention and not
           | solved by the language.
        
         | Avshalom wrote:
         | For those who haven't run into anything about this corner of R
         | before:
         | 
         | https://blog.moertel.com/posts/2006-01-20-wondrous-oddities-...
        
         | broomcorn wrote:
         | That sounds like asking for trouble. Someone coming from any
         | other programming language could easily forget that expression
         | evaluation is stateful. Better to be explicit and create an
         | object representing a expression. Tell me, at least, that the
         | variable is immutable in that context?
        
           | nerdponx wrote:
           | The whole magic is that expressions are in fact just objects
           | in the language. And no, there aren't any immutable bindings
           | here.
        
           | bnprks wrote:
           | The good news is that most variables in R are immutable with
           | copy-on-write semantics. Therefore, most of the time
           | everything here will be side-effect-free and any weird
           | editing of the variable bindings is confined to within the
           | function. (The cases that would have side effects are very
           | uncommonly used in my experience)
        
         | empyrrhicist wrote:
         | I saw a funny presentation where Doug Bates said something
         | like: "This kind of evaluation opens the door to do many
         | strange and unspeakable things in R... for some reason Hadley
         | Wickham is very excited about this."
        
         | delusional wrote:
         | > I think software engineers often get turned off by the weird
         | idiosyncrasies of R
         | 
         | That was at least true when I was looking at it. I didn't get
         | it, but the data guys came away loving it. I came away from
         | that whole experience really appreciating how far you can get
         | with an "unclean" design if you persist, and how my gut feeling
         | of good (with all the heuristics for quality that entails) is
         | really very domain specific.
        
         | csimon80 wrote:
         | A lot of the time you're not actually using what is passed to
         | the function, but instead the name of the argument passed to
         | the function (f(x), instead of f('x')). Which, helps the user
         | with their query (dplyr) or configuration (ggplot2).
        
       | adregan wrote:
       | I had been wanting to sign up for exercism, and I love APL, so
       | this was a good nudge. However, I'm browsing the language tracks,
       | and I don't see APL. I see this post is from July 2023--has the
       | APL track been removed since then? Or am I just looking in the
       | wrong place?
        
         | jasonpeacock wrote:
         | From the post:
         | 
         | > APL isn't on the list of [Exercism] languages but I've seen
         | it in codegolf (codegolf.stackexchange.com) solutions often
         | enough that it seemed worth a look.
        
           | adregan wrote:
           | Thanks. I think I parsed that as "isn't on the list of
           | languages that I had wanted to learn."
        
       | anthk wrote:
       | J it's interesting too, without the non-ASCII mess:
       | 
       | https://www.jsoftware.com/indexno.html
       | 
       | https://code.jsoftware.com/wiki/System/Installation <- install
       | 
       | https://code.jsoftware.com/wiki/Guides/Getting_Started <- help
        
       | bruturis wrote:
       | >> find the GCD (greatest common divisor) of the smallest and
       | largest numbers in an array
       | 
       | Just for a short comparison, In J the analogous code is </ +. >/
       | Where / is for reduce, +. is for the GCD,  the LCM is *.
       | The basic idea of J notation is using some small change to mean
       | the contrary, for example {. for first and {: for last, {. for
       | take and }. for drop (one symbol can be used as a unary or binary
       | operator with different meaning.  So if floor is <. you can guess
       | what will be the symbol for roof. For another example /:~ is for
       | sorting in ascending order and I imagine that you can guess what
       | is the symbol for sorting in descending order.  In a sense, J
       | notation include some semantic meaning, a LLM could use that
       | notation to try to change an algorithm.  So perhaps someone could
       | think about how to expand this idea for LLM to generate new
       | algorithms.
       | 
       | The matrix m, the sum of the rows, and the maximum of the sum of
       | the rows in J (separated by ;)                 m ; (+/ m) ; >./
       | +/ m       +-----+-------+--+       |0 1 2|9 12 15|15|       |3 4
       | 5|       |  |       |6 7 8|       |  |       +-----+-------+--+
        
       | AndyKluger wrote:
       | Not an array language (AFAIU), but here are some of the mentioned
       | problems solved in (glorious) Factor:                   : find-
       | gcd ( nums -- gcd )           [ infimum ] [ supremum ] bi gcd nip
       | ;              : max-wealth ( accounts -- n )           [ sum ]
       | map-supremum ;              : which-max-wealth ( accounts -- i )
       | [ sum ] supremum-by* drop ;              primes-upto
        
       | cl3misch wrote:
       | > what if we just generate all products from the set of numbers
       | 2:n and exclude those as "not prime" from all the numbers up to
       | n?
       | 
       | It's fun to translate terse APL to somewhat terse numpy. The
       | result still can be very compact and you can parse it easily if
       | you're used to looking at numpy:                   s = arange(2,
       | 50); p = outer(s, s).ravel(); sorted(set(s) - set(p))
        
         | jonocarroll wrote:
         | What's interesting there is that numpy is inspired (more than a
         | little) by APL and aims to bring that 'array' thinking to
         | python. I agree that thinking in this 'array' way helps to
         | better construct a solution in any language, so I'm leaning
         | towards 'designing' with APL glyphs, even if that's not the
         | language I'm implementing the thing in.
        
           | nerdponx wrote:
           | If it takes any inspiration from APL, it would be mostly
           | indirect, via Matlab.
        
             | jonocarroll wrote:
             | I've seen the connection made here
             | https://dev.to/bakerjd99/numpy-another-iverson-ghost-9mc
             | though the link to the source quote is broken. In all
             | fairness, Matlab is itself inspired by APL.
        
         | bruturis wrote:
         | Analogous code in J,                 /:~ s -. p [ p =: s*/s [
         | s=: 2+i.48
         | 
         | An exercise for numpy, test that GCD(x,y) * LCM(x,y) = x*y
         | using 1000 random numbers in the range 0..99 for x e y.
         | test =:  (* = *. * +.) & ?       *./ test~  1000 # 100
        
       | jonocarroll wrote:
       | (author here, still getting over the first time I've seen one of
       | my own posts on this site)
       | 
       | The many recommendations for J here are a great nudge for me to
       | give it a proper go. I've taken quite a liking to the traditional
       | APL glyphs ( see a photo of the stickers on my laptop keys in
       | this post https://jcarroll.com.au/2023/12/10/advent-of-array-
       | elegance/ ) so I'm not looking for a way to avoid them.
       | 
       | Another detraction I've seen around is about the ambivalence of
       | APL glyphs (taking either 1 or 2 arguments and doing something
       | different in each case). I don't particularly mind it because I
       | think it becomes more natural to "understand" how a function is
       | being used the more familiar you become with it, but without the
       | limitation on the number of glyphs, I can see the benefit of
       | separating those.
        
       ___________________________________________________________________
       (page generated 2024-03-21 23:00 UTC)