From J Wiki
Jump to navigation Jump to search

Beginner's regatta

This question was asked recently on the J-programming forum:

I have no problem selecting items when using numeric values:

   val=. 0 1 { 'mevema'
   val=. 2 3 { 'mevema'

But why do I have a problem when using formulas instead of numeric values?

   j=. 0                          NB. or 1 or 2
   val=. (2*j) (1+2*j) { 'mevema'
|syntax error
|   val=.    (2*j)(1+2*j){'mevema'

The reasoning behind the user's question is probably that since the formula returns a 0 and a 1, why doesn't it work the same?

Often we figure out the answers to these questions by breaking down the expression into its component parts. So, if we try this with the "formula" alone, we see this:

   (2*j) (1+2*j)
|syntax error
|       (2*j)(1+2*j)

This tells us the formula is not returning "0 1" as assumed. Continuing to break down the failing expression, we might try this:

   n0=. 0
   n1=. 1
   n0 n1
|syntax error
|       n0 n1

Here we are getting to the root of the problem. As someone on the forum pointed out, as expression like "N N", where N represents a noun, is a syntax error in J.

Eventually this boils down to figuring out how to return a single noun with the formula in order to use that for the selection. There are any number of ways of doing this but it may be useful to reflect on the fundamental array nature of the language to notice that the formula does not have to be written as disconnected scalar nouns but as an array expression like this:

   0 1+2*j
0 1

This result then can be used as originally intended:

   (0 1+2*j){'mevema'


Last month we started to outline the code for working with poker. Since this is a rather involved topic, we might consider a simpler version of a poker problem by considering low-only poker. This is a poker variant where all the usual poker hands are discounted to focus on what are essentially the worst poker hands - those that are nothings.

TL;DR: Raul came up with an arguably simpler version than the code I presented, which was this:

lowerAce=: 3 : '((12=1{y)}(1{y),:_1) 1}y'   NB. card rank 12->_1 (ace->1)
raiseAce=: 3 : '((_1=1{y)}(1{y),:12) 1}y'   NB. card rank _1->12 (1->ace)

NB.* bestLow: return best low hand given some cards.
NB. California rules->straights and flushes do not count against low hand,
NB. so we ignore them here.
bestLow=: 3 : 0
   y=. (]/:1{"1]) &.|: lowerAce suitRank y
   y=. (]#"1~1,2~:/\1{]) y                   NB. Remove duplicate ranks
   y=. (5<.{:$y){."1 (]#"1~1,2~:/\1{]) y     NB. Pick lowest 5 if enough
   (([: (|.) 1 {  ]) ; suitRank@:raiseAce) y NB. Ranks, high to low; hand

Raul's version:

require 'stats'          NB. For "comb"
bestLowRM=: 3 : 0        NB. Thanks to Raul Miller
  cards=. y\:13|y
  kinds=. 14|2+13|cards
  hands=. 5 comb #y      NB. Check all 5-card combinations
  ranks=. 13 #. (,.~ [: >./"1 #/.~"1) hands{kinds

Note that the "5 comb..." step may be unnecessary.

Comparing the results of these on some random 9-card selections, we see that Raul's version does not bother with the more complex return value that I had:

      ,/showCards&>,.tests=. 9?&.>5$52
|9S|6H|3H|JH |4D|5S|2D |9C|JS|
|QC|KH|2H|3H |JH|4C|4H |QH|KS|
|7S|4C|2C|2H |8C|2S|10C|3H|AC|
|2S|3S|8S|5S |6S|AC|4D |QC|JC|
|8C|AH|4C|10C|8H|7C|AC |QD|8S|

|4 3 2 1 0 |13 27 15 42 30|
|10 9 2 1 0|26 27 2 35 10 |
|5 2 1 0 _1|12 0 27 2 44  |
|3 2 1 0 _1|12 39 40 15 42|
|8 6 5 2 _1|38 2 5 6 8    |
30 42 15 27 13
10 35  2 27 26
12 44  2 27  0
12 42 15 40 39
38  8  6  5  2

Since the display of low hands has a preferred order of highest to lowest where ace is low, let's take care of that.

   lowOrdering=: ] \: 1 {  [: lowerAce suitRank NB. Show low hands in descending order of rank with ace low.

We get these results:

   (showCards@:lowOrdering)"1 bestLowRM&>tests
|6H |5S|4D|3H|2D|
|QC |JH|4C|3H|2H|
|7S |4C|3H|2C|AC|
|5S |4D|3S|2S|AC|

Which we can also display this way:

   'ExampleLowHandsInPreferredOrder.png' cardImages lowOrdering"1 bestLowRM&>tests

Giving us this:

Advanced topics

Some recent traffic on the J forums about doing linear regression and a poorly-attended question on Reddit about benchmarking APLs got me to thinking about cross-language comparisons. In the forum topic, "Question about least squares with %.", the correspondent compared coefficients from a linear regression in J with those from Matlab and Python where J did not come out well. This sort of cross-language comparison seems like a good initial step for evaluating results from some of the more complex parts of a language.

The Reddit question on r/apljk asks if there is a benchmarking site for APLs. Presumably this is intended to compare performances of different APLs on the same problems as is done in the site to which the questioner referred. This site shows comparisons like this:

Comparative Scheme benchmarks for different versions of the language.jpg

In my response to this question, I asserted that the APL community often puts correctness before performance. However, a cross-language comparison could benefit all languages by providing external checks on the correctness of results as well as the performance of different languages.

Learning and Teaching J

See Green Vs. Brown Programming Languages - are newer languages less "dreaded" because they are attached to fewer legacy systems?

The premise is based on these categories in the Stack Overflow Developer Survey: The Most Dreaded Programming Languages and The Most Loved Programming Language. These rankings are based on this question:

  Which programming, scripting, and markup languages have you done extensive development work in over the past year, and which do you want to work in over the next year? (If you both worked with the language and want to continue to do so, please check both boxes in that row.)
  A dreaded language is one you work with extensively in the current year but don’t want to continue to use. A loved language you use extensively and wish to continue using. The results are interesting because they reflect the opinions of people who are using the languages extensively.

The author, Adam Gordon Bell, compares the results of the two categories and infers that membership on one list or the other has a lot to do with whether or not the language in question is newer or older.

The top 15 most dreaded programming languages are: VBA, Objective-C, Perl, Assembly, C, PHP, Ruby, C++, Java, R, Haskell, Scala, HTML, Shell, and SQL.

The top 15 most loved programming languages are: Rust, TypeScript, Python, Kotlin, Go, Julia, Dart, C#, Swift, JavaScript, SQL, Shell, HTML, Scala, and Haskell.

His speculation is based on the idea that "old code is the worst" and that dreaded languages are likely to be used in existing brown-field projects and [l]oved languages are more often used in new green-field projects.

This seems plausible. In fact, when we look back at the previous "Show-and-tell" section here, we see that Raul's ab initio code looks nicer than my code which is working within an existing framework of code for high-only poker hands.

This also seems plausible based on my own recent experience working with a large legacy system in APL, which is a language I love in part because it makes it so easy to get things done quickly. However, it took me about two days to deliver fewer than 20 lines of code recently, in part because of the time it took me to understand the existing data structures and to figure out which existing routines I should use.

APL Listed on Stack Overflow's 2021 Developer Survey?

Adám Brudzewsky of Dyalog is hoping to get APL listed in Stack Overflows 2021 Developer survey. Check out these links and upvote them if you would like this to happen: APL and the Dyalog development environment.