1. 38
  1.  

  2. 6

    One idea I periodically noodle on: a Tensorflow-like built in J-like built in Mu-like.

    1. 5

      Nice intro.

      I may not use J in my everyday programming, but I’m glad I learned it and think it made me a better programmer.

      This was my experience too, though I continue to use J almost daily even if not professionally.

      Far more than any other language, including Haskell, learning J felt like dropping acid and blasting away everything I thought I knew about programming.

      It’s the third paradigm, and unfortunately the least well-known:

      1. Procedural
      2. Functional
      3. Array

      It really is a whole new mindset.

      1. 7

        How did you learn it? What kind of projects would you recommend to learn such a language to discover its benefits?

        1. 4

          Personally, I stuck to number-crunching a-la Project Euler and some Advent of Code challenges.

          Also tried to use J for bio-signal processing (a set of student labs built around calculating various metrics of heart-rate variability), but after looking at the solution professor went “Nuh-uh” and I had to switch to R, which IMO wasn’t that bad of a compromise in terms of paradigm shift.


          The most interesting point that I don’t see being addressed in most of the J write-ups is how one can use it to create ad-hoc calculi of various sorts, even problem-specific DSLs. Function composition, monadic/dyadic distinction and tacit programming surely allow for that, yet the “how” of it isn’t widely discussed.

          1. 1

            I had to switch to R, which IMO wasn’t that bad of a compromise in terms of paradigm shift.

            That’s a shame: I think R is basically the same as numpy - no real paradigm shift, just more/different functions, so I hope you’ll give Iverson-ish languages another try, because by focusing on the array-ness you might’ve missed something incredible.

            in most of the J write-ups is how one can use it to create ad-hoc calculi of various sorts, even problem-specific DSLs

            I’m very curious to understand better what you’re looking for here. What’s a kind of problem you’d like to see?

            1. 2

              I think R is basically the same as numpy

              That’s true, and NumPy is basically an ugly cousin of APL ;) What I rather meant is that sacrificing J’s expressiveness was a bearable trade-off in the context of my task, and that in the end I didn’t really need most of it: just reusing R’s libraries and mashing matrices together sufficed. Productivity and acceptance by peers over cleverness and personal satisfaction.

              I’m very curious to understand better what you’re looking for here

              “Notation as a tool of thought” I think. Is J a mean to an end as it is given, or does it permit/encourage building linguistic abstractions on top?

              APL is often praised for its lyiricality, and J specifically describes the parts of its speech as nouns, verbs, adverbs, and conjunctions; but does it end there? In J, There are ways to assign obverses and adverses to a verb, to define its monadic and dyadic versions, to create adverbs with conjunctions; and then some tree-manipulating primitives, even ;: for tokenizing, and boxes that permit manipulating J code as data. Is any of that intended for meta-programming, AST building, and ultimately DSL creation?

              Can an expert in their domain take J and carefully design a set of composable primitives for solving specific problems? If so, what is the process behind that, and how does the end result look like? Is it a notation that reads and writes like poetry, or is it a prosaic library? Is it even a normal practice in APL family?

              So, I guess what I am looking for is a walkthrough thru the points I raised, with some interesting problem as its subject; both about the mindset and its execution. I’m too much of a puny human to grasp Aaron Hsu’s thesis on the compiler that he built with Dyalog APL, but the basic premise is roughly the same with what I have in mind. His live stream on this compiler’s design and architecture is also worth watching.

              1. 3

                Is J a mean to an end as it is given, or does it permit/encourage building linguistic abstractions on top?

                Permit? Probably.

                Encourage? I’ve not seen this personally. In fact, the ethos of J/APL seems the opposite of this. The big promise of the language is that with a single set of ~50 primitives you can elegantly solve the vast majority of practical problems. So there’s no need for bespoke DSLs for your different applications.

                As a side note, my experience with Ruby has convinced me that such a DSLs are usually a mistake.

                1. 3

                  A case in point: in the above-mentioned talk from Aaron Hsu, he shows how he defined PEG parser combinators and used them to write parsing expressions in a seemingly declarative manner.

                  Surely that doesn’t qualify as a DSL, but the ability to re-define a problem in terms of these 50+ vector-manipulating primitives is what always fascinated me in APL. There’s an inherent, almost visceral “spatiality” to this act. At times it feels that the more terse your code is, the closer it to some sort of underlying ur-computation that the world is build of.

                  Perhaps my original question is not about how to extend the language towards the problem, but how to ground the problem in the notation. Or perhaps how to design a notation with APL-ish qualities that will influence how I think with it and create in it?


                  APL family posits a certain view on the programming, but how to see everything thru its lens? Is it just linear algebra with mathematical know-how? Practice?

                  An example from my experience: in the first semester of DSP I really struggled with the concept of convolution, I simply couldn’t grasp it on an intuitive level. At least in my native language “convolution” sounds more like “folding” or even “coagulating”, but what folds with what? What is the physical meaning? Implementing it in C-level language only obscured the question behind the semantic noise, by-the-book definitions didn’t help either.

                  And then one day I just [:+//.*/ in J console and it clicked. In a sense, if two signals are threads, then their convolution is a helical braid, the one that you create by coiling one thread over another; a sum +/ of oblique /. diagonals formed by multiplicative * intersections /.

                  There’s a scene in “Matrix: Revolutions” where blinded Neo says to Smith in Bane’s body “I can see you” — that’s the kind of feeling I got from this experience.

                  1. 2

                    APL family posits a certain view on the programming, but how to see everything thru its lens? Is it just linear algebra with mathematical know-how? Practice?

                    Practical answer: doing many problems, getting it “wrong”, and then seeing a more natural way to do it. It seems like you already know this though, based on your very nice example.

                    Larger answer: I’ve been meaning to write about this, but tldr… two words come to mind: geometrical and holistic. Think of the game of life in APL. In J/APL think, you don’t view the problem from the point of view of individual cells. Instead, you look at the whole plane at once, and imagine eight copies of that plane stacked on top of one another – one plane for each directional shift. Then the neighbor count is simply the +/ of those planes.

                    This pattern appears a lot. You take the view from above, look at “everything at once,” and there’s a natural and simple way to express that with array computations. It doesn’t always work, though. Some problems aren’t a good fit for array thinking, but a surprising number are.

                    1. 3

                      Yes, the local action (counting neighbors) is applied on the board as a whole, not just to a specific cell; I even have a J one-liner stashed for that somewhere.† Nice example.

                      Interesting that APL solutions turn out to be fractal in their nature (speaking of ur-computation). Reminds me of Konrad Zuse’s Rechnender Raum and Plankalkül.


                      † Lo and behold:

                      L =: [:+.`*./ ],~ 3 4=/ [:+/^:2 (>{;~i:1)|.]
                      g =: 5 5 $ 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 1 1 0
                      
                         <"_1 ' o' {~ L^:(i.5) g
                      ┌─────┬─────┬─────┬─────┬─────┐
                      │     │     │     │     │     │
                      │  o  │     │     │     │     │
                      │   o │ o o │   o │  o  │   o │
                      │ ooo │  oo │ o o │   oo│    o│
                      │     │  o  │  oo │  oo │  ooo│
                      └─────┴─────┴─────┴─────┴─────┘
                      
                      1. 1

                        Nice. You might also enjoy this 26 byte version:

                        (]=3+4=*)[:+/(>,{;~i:1)&|.
                        

                        By the way, what did you mean by “APL solutions turn out to be fractal in their nature”?

                        1. 2

                          Well, Moore neighborhood is applied to the playing field as a matrix rotation, but at the same time to each cell on the field (each element of a matrix). So, in a way, Game of Life field is a cell by itself (with a number of states dependant on a number of cells in it), and, in turn, each cell on it is a playing board. [1]

                             [ c =: 4=i.3 3
                          0 0 0 NB. A cell with 8 neighbors.
                          0 1 0
                          0 0 0
                             <"_2 (>{;~i:_1)|. c
                          ┌─────┬─────┬─────┐ NB. A cell with 8 neighbors?
                          │1 0 0│0 1 0│0 0 1│
                          │0 0 0│0 0 0│0 0 0│
                          │0 0 0│0 0 0│0 0 0│
                          ├─────┼─────┼─────┤
                          │0 0 0│0 0 0│0 0 0│
                          │1 0 0│0 1 0│0 0 1│
                          │0 0 0│0 0 0│0 0 0│
                          ├─────┼─────┼─────┤
                          │0 0 0│0 0 0│0 0 0│
                          │0 0 0│0 0 0│0 0 0│
                          │1 0 0│0 1 0│0 0 1│
                          └─────┴─────┴─────┘
                          

                          That was a nod towards your idea about geometry and holistic approach.

                          1. 1

                            Gotcha. Thanks.

                  2. 2

                    Yeah. One subtlety most people don’t appreciate about “notation as a tool of thought” is that the paper doesn’t mention “abstraction” once. Easy to miss in these modern times where “notation” has implicitly come to mean “for creating new abstractions”.

                    1. 4

                      That’s fascinating. I never noticed that before.

                      Since I have it open now, relevant paragraph on my previous point:

                      The utility of a language as a tool of thought increases with the range of topics it can treat, but decreases with the amount of vocabulary and the complexity of grammatical rules which the user must keep in mind. Economy of notation is therefore important.

                      Notation as a tool of thought

                      1. 1

                        True, it doesn’t. But then the whole paper is a process of abstraction (deriving general patterns from concrete examples, addressing the main thesis case-by-case) that uses APL as a conceptual vehicle.

                        1. 2

                          The design goal is to create a notation that minimizes the need for new names.

                          1. 3

                            APL is like a beautiful diamond – flawless, beautifully symmetrical. But you can’t add anything to it. If you try to glue on another diamond, you don’t get a bigger diamond. Lisp is like a ball of mud.

                            Extension of the base language is at odds with its core design principle, but that surely does not preclude us from defining problems in terms of it. My original questions (not well-formed TBH) were more concerned with the ways this notation can be adapted to a particular context (or vice versa).

                            E.g. the above-mentioned Co-dfns compiler, as far as I understand, implements a Scheme-like subset of Dyalog APL and represents trees as vectors, but not the other way around (extend the language with tree-like datatype and spruce all of that with s-expressions or something).

                            Like I said, J has a set of primitives and mechanics that to me seem language-oriented, so I wondered how compiler/interpreter creation looks like from this point of view, on a small exemplified scale (hence the DSLs), and what is the problem-solving mindset (heuristics?) behind it.

                            FSM state-transitions can be modeled with tables, yes, and AST, as a graph, can use adjacency matrices with eigen-shticks, but this whole approach feels like a black magic and well-guarded trade secret. Maybe because it’s a fork from the mainstream road and off into the academical weeds. Need to check out more of Aaron Hsu’s talks for sure.

                            1. 1

                              As a historical aside, the APL presented in Iverson’s A Programming Language book (pdf) included trees as a basic data structure (page 45 in the book). They weren’t included in APL as first implemented, then APL2 added nested arrays which serve a similar purpose. Some of the book’s tree operations are in J.

                              1. 2

                                Yes, thanks for mentioning that! The chapter on microprogramming with APL was mind-blowing at the time I read it.

              2. 2

                I learned it mainly by doing hundreds of code golf problems, asking questions on the J IRC channel, reading (good chunks of) J for C programmers and Learning J, as well as the J dictionary and the more accessible NuVoc documentation.

                I’d say it took 1.5-2 years to acquire a feeling of fluency. Much longer than other languages. One crucial practice was solving a problem and then having it edited by experts. Because unavoidably you’ll apply your current paradigms to J, or simply be unaware of J idioms, rather than solving the problem in a “J way.”

                The best place to get this kind of help these days is the The APL Orchard. There’s a handful of very talented J and APL programmers willing to help.

                By the way, you could get the same mind-expansion from learning APL, if you were more inclined that way. The free book on the Dyalog APL site is also good.

              3. 1

                I’d classify it as functional. It just uses a multi-dimensional array where others use a linked list. Nearly all operators are side-effect free and data is immutable. There are higher order patterns like map-reduce.

                1. 3

                  Array programming languages aren’t “functional” or “immutable” in the way that Erlang and ML are, and I observe beginners notice this only after a few months, probably because these features are used in Array-language applications, and not in the puzzles you practice on to learn how to think in Arrays. Real applications batch and use lots of global variables with delimited names like TCL or Perl; J programmers call them locales; K programmers have the K-tree; APL it’s isolates. And so on.

                  I know other languages have “arrays” but it’s just an unfortunate name collision. Many of us use the term “Iverson languages” instead of “Array languages”, because we’re not trying to confuse things unnecessarily.

                  1. 2

                    To add on the sibling comments, the article linked and code golf expose you to a part of J. For me it go in a very different mindset with stuffs like : full tacit programming reaching more a function-level programming [1] (Even point-free in Haskell fill clumsy in comparison with APL and J), constructs like hooks and forks [2] permitting composition and chaining of functions with ease.

                    1. 1

                      It’s true that tacit programming in J is functional, but that misses the larger difference. The way you need to think about and frame a problem to solve it idiomatically is usually quite different in J versus, say, Haskell.

                  2. 4

                    That syntax highlighting on the J code is killing away my thought…

                    I hope there are better ways to do it, but as an after thought, using glyphs like in APL have real advantages here. Mentally putting . and : together with preceding symbol is a pain.

                    1. 4

                      I think syntax highlighting actually has the potential to really help j a lot. If you use it to bind together digraphs and separate them from the surrounding characters, it’s much easier to distinguish the character sequence as a single symbol. (It doesn’t seem to have been used that way here, though.)

                      J uses ascii because when it was created (1989), you couldn’t really rely on the presence of any character sets other than us-ascii. IMO a unicode j is in order.

                      1. 2

                        If you use it to bind together digraphs and separate them from the surrounding characters, it’s much easier to distinguish the character sequence as a single symbol. (It doesn’t seem to have been used that way here, though.)

                        I don’t think this is a good idea. J starts making sense when +./@:E. means “is x in y” and not “any [x] at member” or (even worse) “or insert [x] at member” because the whole point is the notation. Colouring the “parts of speech” works against that goal.

                        However the (specific) issue I think jxy was pointing to is that “i.” is two-tone on this blog, even though it’s a single verb, and I think we can agree that’s terrible, no?

                        1. 2

                          J starts making sense when +./@:E. means “is x in y” and not “any [x] at member” or (even worse) “or insert [x] at member” because the whole point is the notation. Colouring the “parts of speech” works against that goal.

                          Does it? We still recognise idioms in written english where words are homogenously spaced (more or less—most spacing isn’t between sentences or paragraphs), even though idioms exist on scales both larger and smaller than a single word. The first step for (human) parsing of written language is still breaking it up into lexemes. And I think that separate colouration for multi-character lexemes is useful to that end.

                          1. 2

                            Does it?

                            Yes! Imagine if ever y time we use d a suffix or a compound word, we add ed white space. You could very easy -ily convince your self you are look ing at English, but it is still strange.

                            The first step for (human) parsing of written language is still breaking it up into lexemes.

                            Only when you’re still a begnner. When you are comfortable reading English, you willl tolerate misspellings, and transposed letters without ever noticing them..

                            1. 3

                              Fair enough.

                        2. 2

                          Unicode J is an interesting idea. Does anyone know of any APL or J apps for mobile devices? It occurs to me that they might be a good model for touchscreen development.

                          1. 2

                            J is written in portable C and is available for Windows, Linux, Mac, iOS, Android and Raspberry Pi. [1]

                            It is just a pain to find it. I had it on my android phone during a time.

                            [1] https://www.jsoftware.com/#/README

                            1. 2

                              An older version of j is on ios, and there also seems to be one for android.

                              dzaima/apl has an android version.

                        3. 3

                          I wonder if it would be feasible to build a gpu accelerated version of APL/J.

                          1. 4

                            Yes. It has/is being done by Aaron Hsu. it was their thesis and now it is being funded by Dyalog afaik

                            https://github.com/Co-dfns/Co-dfns

                            1. 2

                              As the sibling mentions, aaron hsu made a gpu-accelerated apl. I also think dyalog is working on something; their careers page used to say they wanted experience in opencl.

                            2. 2

                              There’s a nice(ish) Perl idiom for getting the grade that’s probably adaptable to several other dynamic languages. Where

                              @sorted = sort { $a <=> $b } @foo
                              

                              means “sort @foo numerically and put the result in @sorted”,

                              @grade = sort { $foo[$a] <=> $foo[$b] } 0 .. $#foo
                              

                              means “sort the indices of @foo using numeric comparison of the element at that index and put the result in @grade”, and

                              @sorted = @foo[@grade]
                              

                              will recover the actual sorted list of values, but like with APL or J, you have the option to apply that permutation to another list, or do other interesting things to it. Mostly it comes in handy for sorting “parallel arrays” (which are usually a bad idea to have in the first place, but sometimes they’re impractical to remove), but occasionally you see a more creative use.

                              1. 2

                                When I was doing much of exploratory programming for satellite images, I wished to have a terse language with array first manipulation as J. Julia is very nice middle ground, imho better than python + numpy, that take inspiration from array-oriented language. It also integrate UTF-8 symbols in the syntax reducing the frictions between the maths and programming counterpart.

                                1. 1

                                  Sincere question: IIUC Matlab/Octave, R, Julia, all operate on arrays too. What does J/APL bring on the table in comparison nowadays (apart from being an inspiration for those, I assume)? (Sorry if that’s explained in the article, don’t have time to read it now unfortunately.)

                                  1. 1

                                    The clearest explanation is probably in the seminal paper/presentation Notation as a Tool of Thought. Longer than TFA, but should answer all your questions; read it.

                                  2. 1

                                    To plug in my favorite Iverson language, QNial

                                    Generating primes:

                                    primes is sublist [ each (2 = sum eachright (0 = mod) [pass,count]), pass ] rest count
                                    primes 10
                                    |2 3 5 7