Live data from Hacker News

J Notation as a Tool of Thought

hillelwayne.com

11–20 of 60 posts

Re: J Notation as a Tool of Thought

#11

Earlier quoted context omitted.

You've reproduced the most trivial example, which many languages make easy. I would be very interested to see another language with a rank operator, for instance. ------------------------------------------------------------------------ Challenge for you: rewrite a nontrivial program in one of those frameworks, with the following restrictions: - No iteration (including implicit iterations—map, filter; reduce is ok) -…

Rank Is actually implicitly done by numpy using a mechanism called broadcasting. For example: >>> np.array([10, 20, 30]) + np.array([[1,2,3], [4,5,6], [7,8,9]]) array([[11, 22, 33], [14, 25, 36], [17, 28, 39]]) Sieves exist in numpy, called masks: >>>np.array([10, 20, 30]) > 15 array([False, True, True]) Of course they can be operated on just like any other numpy array. Grades exist in numpy: >>>np.array([5,4,3,2,1])…

> Rank Is actually implicitly done by numpy using a mechanism called broadcasting.

Numpy's broadcasting is scalar conformability, to which the rank operator (and general conformability) provides a general case. Example in j:

     ] x =. i. 2 3 4                                                                                                                   
   0  1  2  3
   4  5  6  7
   8  9 10 11

  12 13 14 15
  16 17 18 19
  20 21 22 23
     ] y =. i. 3 4
  0 1  2  3
  4 5  6  7
  8 9 10 11
     x + y         NB. this will error because + expects that, if its arguments' shapes are not the same, one will be a prefix of the other
  |length error
  |   x    +y
                   NB. this is easy enough to fix, however
     x +"2 y       NB. +"2 is shorthand for +"2 2; meaning, choose rank-2 arrays from both the left and right arguments
   0  2  4  6
   8 10 12 14
  16 18 20 22

  12 14 16 18
  20 22 24 26
  28 30 32 34
Numpy will actually do this without the rank operator, because it uses suffix agreement rather than prefix agreement (which is absolutely bonkers—j used suffix agreement for about 5 minutes in 1990, before realising it was an awful idea). For for numpy, see if you can add:

  np.array([[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]) + np.array([[0, 1, 2], [3, 4, 5]])
Intelligently. (I'm sure it's not overly difficult to come up with a solution, but can you do it with a single higher-order function call which generalises to other argument shapes?)

(The j equivalent, (i. 2 3 4) + (i. 2 3) also works without trouble.)

  ------------------------------------------------------------------------
Another example, which may be more illustrative, is the ability to perform reductions along arbitrary axes. For example:

     ] x =. i. 4 3
  0  1  2
  3  4  5
  6  7  8
  9 10 11
     +/ x       NB. sum reduced along leading axis, the default, producing an array of shape 3
  18 22 26
     +/"1 x    NB. sum each rank-1 array (vector); or, reduce last axis, producing an array of shape 4
  3 12 21 30

  ------------------------------------------------------------------------
Another curiosity, which I have thus far neglected, is the extent to which numpy's being 'a little more verbose' is actually incredibly important in shaping the way you approach and think about problems. The great-uncle comment also addresses this, but Iverson probably says it better than either of us can: read https://www.jsoftware.com/papers/tot.htm

Re: J Notation as a Tool of Thought

#12
In J, I think it's very difficult to move on from the initial stage of dealing with "line noise" as the author mentions.

For me, this was further complicated by the fact that error messages are very hard to understand in the beginning.

I've written an article that describes how I typically deal with solving most of the domain/rank/length errors: https://www.justus.pw/posts/2020-07-31-errors-in-j.html

Re: J Notation as a Tool of Thought

#13
This seems very interesting for numerical computation, but at first glance few of these operations seem to apply directly to general computation (I'm sure that there are isomorphisms that can be used to apply them indirectly).

The example with sorting was the oddest from this point of view. The author praised the idea of the permutation vector as being a relatively direct mathematical specification of sorting (return the permutation of the original array in sorted order) while leaving out the 'sorted' part. Also, this focuses entirely on the result, but there is no word on the algorithm - 'how is the array sorted' is the question that computer science is designed to solve, as opposed to 'what are the fixed points of a sorted array'.

As such, as someone with no experience of J, I'm left wondering if this is another example of the infamous Haskell quicksort - well-picked examples of code which produces a desired result are extraordinarily terse and expressive, but actually implementing well-known algorithms is often just as verbose as C, give or take.

Re: J Notation as a Tool of Thought

#14

Earlier quoted context omitted.

You've reproduced the most trivial example, which many languages make easy. I would be very interested to see another language with a rank operator, for instance. ------------------------------------------------------------------------ Challenge for you: rewrite a nontrivial program in one of those frameworks, with the following restrictions: - No iteration (including implicit iterations—map, filter; reduce is ok) -…

I have want to chime in. Agree, it is great that ideas from APL have made it into the language... But there is, fortunately, a long and fruitful path still to explore... I love that J is like an alternative path to functional approaches like Haskell and how it plays in terms of providing expressive power. Still, I will not create code in J that is maintained jointly with other users from other domains (which is the c…

I like how APL made it into Common Lisp wholesale. There's a library that compiles APL to Common Lisp, allowing you to mix APL and Lisp code, working on the same data structures with both languages.

https://github.com/phantomics/april

Example session I just did, copying APL code from https://aplwiki.com/wiki/John_Scholes%27_Conway%27s_Game_of_...:

  CL-USER> (april:with-april-context ((:space *lifespace*))
             (april:april "Show←{'·⌺'[⎕IO+⍵]}")
             (april:april "glider←3 3⍴1 1 1 1 0 0 0 1 0")
             (april:april-f "Show glider")
             (print (april:april "glider")) ; to prove it's a Lisp array
             (terpri)
             (april:april "grid←¯10 ¯10↑glider")
             (april:april-f "Show grid")
             (terpri)
             (april:april "life ← {⊃1 ⍵ ∨.∧ 3 4 = +/ +⌿ ¯1 0 1 ∘.⊖ ¯1 0 1 ⌽¨ ⊂⍵}")
             (terpri)
             (april:april-f "Show¨{life⍣⍵⊢grid}¨0,⍳3")
             (terpri))
  ⌺⌺⌺
  ⌺··
  ·⌺·

  #2A((1 1 1) (1 0 0) (0 1 0))
  ··········
  ··········
  ··········
  ··········
  ··········
  ··········
  ··········
  ·······⌺⌺⌺
  ·······⌺··
  ········⌺·


   ··········  ··········  ··········  ··········
   ··········  ··········  ··········  ··········
   ··········  ··········  ··········  ··········
   ··········  ··········  ··········  ··········
   ··········  ··········  ··········  ··········
   ··········  ··········  ··········  ··········
   ··········  ········⌺·  ·······⌺⌺·  ·······⌺⌺·
   ·······⌺⌺⌺  ·······⌺⌺·  ·······⌺·⌺  ······⌺⌺··
   ·······⌺··  ·······⌺·⌺  ·······⌺··  ········⌺·
   ········⌺·  ··········  ··········  ··········
(APL being compiled to Lisp is important, not just because it gives you proper interoperability out of the box, but also because on implementations like SBCL this means APL code will get compiled, through Lisp, to native code. And you can do that at runtime too.)

Now I wish I could find something that does the same for J, because I'm sure as hell not going to buy an APL-friendly keyboard.

Re: J Notation as a Tool of Thought

#15

This reminded me very much of working in R or working with Numpy. I however always thought having an array as the primitive in R was great only because R is focused on statistics and data science. My understanding is that J claims to be general purpose programming and as such I’m surprised the paradigm holds.

If you run the J GUI, written in J, it is going with blow your mind about how general purpose it is...

Re: J Notation as a Tool of Thought

#16

This seems very interesting for numerical computation, but at first glance few of these operations seem to apply directly to general computation (I'm sure that there are isomorphisms that can be used to apply them indirectly). The example with sorting was the oddest from this point of view. The author praised the idea of the permutation vector as being a relatively direct mathematical specification of sorting (return…

Yes, once one goes really deep, it's more like C in the end. One good thing I find about J is that you can still have a clear picture in your mind about how it will be executed, without actually having to write the details yourself. It also ties with SICP lesson of developing a language over a language with right abstractions at each level.

Re: J Notation as a Tool of Thought

#17

This seems very interesting for numerical computation, but at first glance few of these operations seem to apply directly to general computation (I'm sure that there are isomorphisms that can be used to apply them indirectly). The example with sorting was the oddest from this point of view. The author praised the idea of the permutation vector as being a relatively direct mathematical specification of sorting (return…

> there is no word on the algorithm - 'how is the array sorted' is the question that computer science is designed to solve, as opposed to 'what are the fixed points of a sorted array'

'[H]ow is the array sorted' is one question that computer science can be used to solve. However, assuming it has been solved (which, for many cases, it has), a much more interesting question is 'what can we do with a sorted array'; or, 'given that sorting has such-and-such time or memory complexity, how hard is this other algorithm?' The OP isn't showing off a particular sorting algorithm, he's showing off a sorting interface, because that's more novel in context.

Sorting according to a predicate could be done with outer product/table+reduction, but usually you don't need anything like that. Let's say you have an array of 3-vectors, and you want to sort the vectors according to the 2nd item in each vector. So your sort predicate is v1[1]

     ] x =. ?@] 9 3$10                                                                                                                 
  2 4 9
  3 8 2
  8 0 4
  3 9 6
  3 1 8
  2 6 8
  1 2 5
  9 4 0
  5 0 9
     (

Re: J Notation as a Tool of Thought

#18
post #8
post #6

Earlier quoted context omitted.

Comparing numpy to J is like comparing a dirty rag to a designer suit. The examples you've listed are trivial; the power of J and other array languages cannot be appreciated from afar. The philosophy behind array languages runs much deeper than adding two arrays or transposing matrices.

Can you give an example of something that can be done in J that can't be done easily in numpy?

It's more about expressiveness and the ability to stay at a "high level" than actually the ability to just do some computation that is really hard elsewhere.

After all, most programming languages can do "the same stuff" - but no one would compare Haskell to PHP.

In most of the examples in the article, the author is using just one or two verbs put together. Imagine if all of the verbs in your language worked seamlessly at the "concept" level, rather than the "write the loop" level.

Even functional constructs like map/filter/reduce take up a lot of words. One or two characters can do the same thing, and be read faster and more idiomatically by an astute practitioner.

That's my take on it (as an on and off Q/Kdb user, not a J dude -- yet..)

Re: J Notation as a Tool of Thought

#19

Earlier quoted context omitted.

I have want to chime in. Agree, it is great that ideas from APL have made it into the language... But there is, fortunately, a long and fruitful path still to explore... I love that J is like an alternative path to functional approaches like Haskell and how it plays in terms of providing expressive power. Still, I will not create code in J that is maintained jointly with other users from other domains (which is the c…

I like how APL made it into Common Lisp wholesale . There's a library that compiles APL to Common Lisp, allowing you to mix APL and Lisp code, working on the same data structures with both languages. https://github.com/phantomics/april Example session I just did, copying APL code from https://aplwiki.com/wiki/John_Scholes%27_Conway%27s_Game_of_... : CL-USER> (april:with-april-context ((:space *lifespace*)) (april:apr…

Emacs has an excellent APL keyboard implementation (via gnu-apl-mode) which uses . as a prefix for the apl keys.

Re: J Notation as a Tool of Thought

#20

Earlier quoted context omitted.

I have want to chime in. Agree, it is great that ideas from APL have made it into the language... But there is, fortunately, a long and fruitful path still to explore... I love that J is like an alternative path to functional approaches like Haskell and how it plays in terms of providing expressive power. Still, I will not create code in J that is maintained jointly with other users from other domains (which is the c…

I like how APL made it into Common Lisp wholesale . There's a library that compiles APL to Common Lisp, allowing you to mix APL and Lisp code, working on the same data structures with both languages. https://github.com/phantomics/april Example session I just did, copying APL code from https://aplwiki.com/wiki/John_Scholes%27_Conway%27s_Game_of_... : CL-USER> (april:with-april-context ((:space *lifespace*)) (april:apr…

> APL being compiled to Lisp is important, not just because it gives you proper interoperability out of the box, but also because on implementations like SBCL this means APL code will get compiled, through Lisp, to native code

Except that simd in lisp isn't great and needs to be done mostly by hand[1]; and simd is super important for making apl performant. Also because gc attributes that are good for lisp aren't great for apl. Also because compiling to native code doesn't actually really affect performance of apl, and might actually harm it for larger programs.

To be clear, april is a super-cool project, but not because of any of its performance characteristics.

> Now I wish I could find something that does the same for J, because I'm sure as hell not going to buy an APL-friendly keyboard.

You don't need a special keyboard, just a layout. I don't know how it works on windows (there's an 'IME', I think?) or macos, but x comes with a keyboard layout. I use this:

  setxkbmap -layout us,apl -variant dyalog -option grp:rwin_switch
Which makes it so that holding down the right super key and pressing any key produces an appropriate apl symbol. You may want to use a different key to switch; check 'man xkeyboard-config' and then search for 'Switching to another layout' for other options. Try: modifier key (whatever it is)+r, for ⍴ (rho).

1. https://www.reddit.com/r/lisp/comments/fkfgjn/sbcl_with_simd...

Post reply on HN