[caution: i have been interrupted several times while composing this
message. I been trying to make things consistent but if something
looks inconsistent you should assume that your observations are
accurate and then experiment to find out what really happens.
Assuming, of course, you have time...]

Personally, I am fond of making sure people understand the basics. So
let's take the line that Dan advertised as being sneaky:

   RE =. +1 :n=. |. <;._2 noun define

J executes its sentences from right to left.  So the first word it
encounters is 'define' which has the definition (: 0). In addition to
being a perhaps cute smiley, this is the 'explicit definition' defined
at http://www.jsoftware.com/help/dictionary/d310n.htm

Since that's pretty much the whole language, let's kind of skip over
it and just accept, for now, that it's defining something.

The next word encountered is 'noun' which has the definition (0).
Zero, if you recall, is the thing that if you add 3 to it you get 3.
In other words, it's just a number.

Anyways, when we combine 0 and (: 0) we get (0 : 0) - when executed,
the J interpreter grabs subsequent lines from the session until
terminated by a closing parenthesis. (This is, perhaps, a slight nudge
at the lisp crowd, who use the closing parenthesis for a similar
purpose despite their lack of respect for individual lines.) The
result of evaluating (0 : 0) will then be those lines. (This can be
fun to play with.)

Anyways, at this point we have executed two rules from
http://www.jsoftware.com/help/dictionary/dicte.htm

The first rule was 3 Adverb and the second rule was the '4 Conj' rule
listed near the bottom of the page.

This second rule has the pattern:

   EDGE+AVN    VERB+NOUN    CONJ    VERB+NOUN    4 Conj

In other words, when executing a sentence, J is looking at four of the
elements of the sentence (perhaps worth noting that some of those
elements can be empty - this is important for ending a sentence) and
for this rule, those elements must match this pattern:

leftmost (EDGE+AVN): the emptiness off the left side of the sentence
an assignment operator, a left parenthesis, or an adverb or a verb or
a noun.

next from the left (VERB+NOUN): a verb or a noun

next after that (CONJ): a conjunction

rightmost: (VERB+NOUN): a verb or a noun.

In this example, both of the VERB+NOUN values were the number 0, and
the CONJ was the explicit definition symbol. (Hopefully this is
explicit enough?)

Anyways, here's a more mechanical description of how this shift reduce
grammar works:

sentence:    RE =. +1 :n=. |. <;._2 noun define

parsed into tokens:
   ;:'   RE =. +1 :n=. |. <;._2 noun define'
┌──┬──┬─┬─┬─┬─┬──┬──┬─┬──┬──┬────┬──────┐
│RE│=.│+│1│:│n│=.│|.│<│;.│_2│noun│define│
└──┴──┴─┴─┴─┴─┴──┴──┴─┴──┴──┴────┴──────┘

(If your email client messes up the display of that result, just
execute the sentence for yourself in a J interpreter. That should
reproduce the same result.)

Once J has the sentence and has parsed it into tokens, it can treat
the result as a queue, shifting the rightmost element from the queue
onto its evaluation stack (and then after each shift doing a pattern
match against the parsing rules and executing the first match). If
nothing matches, J performs no operation and attempts another shift.
Name resolution happens when a name is shifted from the first position
on the stack to the second.

So at the point the '3 Adverb' rule triggered, the queue looked like this:

   RE  =.  +  1  :  n  =.  |. <  ;.

And the stack looked like this:

leftmost:       _2
next left:      0
next left:      : 0
rightmost:

The parsing rule for 3 Adverb look like this:

EDGE+AVN    VERB+NOUN    ADV    ANY    3 Adverb

The '3 Adverb' off on the right hand side is just a label and not a
part of the rule itself.

Also the 'VERB+NOUN' and 'ADV' parts of the rule are highlighted.
That's not portable to email. Highlighted means that that's the part
of the rule whose values are used in the execution (and these used
values will be removed and replaced with the result of the execution
of the rule).

So after executing 3 Adverb the stack looks like this

leftmost:       _2
next left:      (lots of text)
next left:
rightmost:

Anyways, after completing an execution J goes back to doing its
shifting (and pattern matching (and maybe some execution as well), and
when the next execution comes around, the queue looks like this:

   RE  =.  +  1  :  n  =.

and the stack looks like this:

leftmost:       |.
next left:      <
next left:      ;.
rightmost:      _2
next right:      (lots of text)

J only inspects the top four elements of the stack during pattern
matching but the stack itself will have an arbitrary depth.

And, remembering our '4 Conj' rule, it was:
   EDGE+AVN    VERB+NOUN    CONJ    VERB+NOUN    4 Conj

and if you looked up that parsing and execution page in the
dictionary, you'd see that both the VERB+NOUN entries were highlighted
as was the CONJ. So the part being executed here is < ;. _2 and those
glue together to get a verb that splits on a final delimiting
character, chopping it off, and boxing each resulting string. And
since we know that our final character in this case will be a newline
character, we can call the expected result here a list of boxed lines.

For our next step, the queue looks like this:

   RE  =.  +  1  :  n

and the stack looks like this:

leftmost:      =.
next left:      |.
next left:     <;._2
rightmost:      lots of text

And the rule being executed is '1 Monad', and the elements being
processed are the two rightmost.

For our next step in execution, the queue looks like

   RE  =.  +  1  :  n

and the stack looks like

leftmost:     n
next left:      =.
next left:      |.
rightmost:      boxed lines

Again, the '1 Monad' rule should trigger, reversing the list of boxes.

Now here is a subtle issue which I am not completely certain about: I
believe that the next execution step occurs without moving anything
from the queue. The '7 Is' rule should kick in here, with the stack
being:

leftmost:      n
next left:      =.
next left:      reversed boxes of lines
rightmost:

This step should set the local value 'n' and should have a result
which is the reversed boxes of lines.

After some more shifting, the queue should look like this:

   RE =.

And the stack should be:

leftmost:      +
next left:      1
next left:      :
rightmost:      reversed boxes of lines

Here, '4 Conj' takes action and the result is an adverb.

Next, we get a queue of

   RE

and a stack of

leftmost:      =.
next left:      +
next left:      1 : (reversed boxes of lines)
rightmost:

and the '3 Adverb'  rule takes action. The boxed lines are then
evaluated as the body of this adverb.

Next our queue is empty, and our stack looks like

leftmost:      R
next left:      =.
next left:      evaluated result
rightmost:      empty

Finally, we have this:

leftmost:      empty queue marker
next left:      evaluated result
next left:
rightmost:

And no rules can trigger here, and since the queue is now empty for
real, no syntax error is triggered and we are done executing the
sentence. (I showed the queue as having only the supplied tokens, but
really there's an "end of queue" token on the far left that we needed
to make this last step work right.)

Anyways, hopefully I did not make too many mistakes here, and you can
either understand something of how J's parsing works despite my
mistakes or you can at least understand enough to ask questions about
the things I have not treated properly.

Thanks,

-- 
Raul

On Wed, Oct 2, 2013 at 11:35 PM, inv2004 . <[email protected]> wrote:
> Thank you very much! Sorry I cannot answer something about it right now,
> because I need much more time to read it and to understand.
>
> But I see none of < > and { :)
>
> Thank you,
>
>
> On Wed, Oct 2, 2013 at 10:04 PM, Dan Bron <[email protected]> wrote:
>
>> Alexander (inv2004) wrote:
>> > Description I am trying to calculate:
>> > http://www.usacycling.org/news/user/story.php?id=580
>> > source data: https://dl.dropboxusercontent.com/u/34917039/2013.txt
>> > J source: https://dl.dropboxusercontent.com/u/34917039/1.j
>>
>> I knocked together an implementation in J (based on my perhaps-mistaken
>> understanding of your problem):
>>
>>
>> http://jsoftware.com/svn/DanBron/trunk/uncategorized/scoreRoadRace.ijs
>>
>> It didn't take very long to code, but unfortunately it would take much
>> longer to explain it in prose.  Also, the style is very peculiar to me,
>> which means it's dense, and uses some sneaky tricks, so even veteran J
>> programmers may find it obscure (e.g. executing the first paragraph, which
>> defines 'RE', in reverse order).
>>
>> I know your goal wasn't to solve this little race scoring puzzle, but to
>> use
>> the puzzle as a means to learn J. So, if I get some more time over the
>> week,
>> I may select and dissect pieces of the code.
>>
>> In the meantime, it may be worth your while to play with it on your own. If
>> you want to do that, it'll probably be easiest and most fruitful to break
>> it
>> into pieces and try them out, interactively, in the J session.
>>
>> So I recommend you replace all the local assignments (=.) with global
>> assignments (=:), so all the intermediate names will be available to
>> inspect
>> and play with individually*.
>>
>> For example, I think you'll be interested in 'score' and 'catSumCount' (and
>> their respective dependencies), because these are the heart of the problem
>> and also highlight how J expresses such ideas differently, and perhaps more
>> elegantly, than other programming languages:
>>
>>            score 1+i. 3       NB. Fewer than 5 racers
>>         0 0 0
>>            score 1+i. 5       NB. 5 racers
>>         3 2 1 0 0
>>            score 1+i. 10      NB. 10 racers
>>         3 2 1 0 0 0 0 0 0 0
>>            score 1+i. 11      NB. 11 racers
>>         7 5 4 3 2 1 0 0 0 0 0
>>
>>
>>            pointGroup 1+i. 3  NB. Fewer than 5 racers
>>         0
>>            pointGroup 1+i. 5  NB. 5 racers
>>         3 2 1
>>            pointGroup 1+i. 10 NB. 10 racers
>>         3 2 1
>>            pointGroup 1+i. 11 NB. 11 racers
>>         7 5 4 3 2 1
>>
>>
>>            pointGroup
>>         (0;3 2 1;7 5 4 3 2 1;8 6 5 4 3 2 1;10 8 7 6 5 4 3 2 1) {::~ 4 10 20
>> 49 I. #
>>
>>
>>            catSumCount 8 7 10 0 3 0 0 0 1 NB. 9 races, score=29, category=3
>>         +-+--+-+
>>         |3|29|9|
>>         +-+--+-+
>>            catSumCount 5 4 0 7 NB. 4 races, score=16, category=4
>>         +-+--+-+
>>         |4|16|4|
>>         +-+--+-+
>>            catSumCount 3000 NB. 1 race, score=super high, but still
>> category=4
>>         +-+----+-+
>>         |4|3000|1|
>>         +-+----+-+
>>
>>            catSumCount
>>         +/ (category ; ;) #
>>
>>            (+/ category #) 8 7 10 0 3 0 0 0 1
>>         3
>>
>>            (+/ , #) 8 7 10 0 3 0 0 0 1
>>         29 9
>>
>>            29 category 9  NB. x=sum of scores, y=# of races
>>         3
>>            35 category 7
>>         1
>>            35 category 2
>>         1
>>            33 category 5
>>         2
>>
>>            category
>>         4 <. 1 + 35 30 20 I. (* 2&<:)
>>
>> It's worth noting the core parts of the scoring algorithm, 'pointGroup' and
>> 'category', are both based on the dyad I. [1]. This is because those parts
>> of the scoring system are defined in terms of ranges (a race of 5 to 10
>> riders, a race of 11 to 20 riders vs. a total score from 0 to 20, a total
>> score from 21 to 30, etc).
>>
>> The dyad I., interval index, is a sterling example of the expressivity and
>> economy of J's notation. Here, it allows us to define these ranges by their
>> essential characteristics, the demarcation lines between levels, rather
>> than
>> the (repetitive, superfluous) contents of each level. Not only is this
>> convenient, but critically, it allows these essential characteristics stand
>> out in our code, rendering it at once briefer and clearer.  The
>> fundamentals
>> are immediately exposed.
>>
>> For example, compare 'category' with the original 'cat' or 'pointGroup'
>> with
>> the original 'points'. Heck, compare the code defining GROUPs to the table
>> in the official scoring site you linked!  Sometimes, formalizing a problem
>> makes it even clearer than the specification.  And, that little itch you
>> feel to start playing with these rules, now that they're exposed and
>> accessible?*  That's what we mean when we say the notation is "suggestive".
>>
>> I hope this gives you a flavor of the benefits, and joys, of J.
>>
>> -Dan
>>
>> *  And because it's really easy to do, given J's short feedback loop and
>> interactive nature.
>>
>> [1]  Definition of the dyad I., "Interval Index"
>>      http://www.jsoftware.com/help/dictionary/dicapdot.htm
>>
>>
>>
>> ----------------------------------------------------------------------
>> For information about J forums see http://www.jsoftware.com/forums.htm
>>
>
>
>
> --
> Regards,
>   Alexander.
> ----------------------------------------------------------------------
> For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to