A one line version of your verb
codeinsertJB3 =: 4 : '> (''('' , ] , op , '')'' ,~ [) each/ |. y [ op=.''
'',x,'' '''
The verb version runs faster on your benchmark, even when the tacit adverb is
bound, but the adverb can be bound:
'and' codeinsert NB. returns tacit verb
[: > ('(' , ')' ,~ [ , ' ' , 'and' , ' ' , ])~&.>/@:|.
Sometimes I do think for hours about whether to make something a verb or
adverb. In this case, a tacit adverb seemed natural, and heuristically assumed
it would be fast. On a different more typical benchmark, it actually is, even
without the adverb being bound: (many sets of 5 items instead of one big large
array)
5 timespacex '''and''&codeinsertJB3("1) 2000 5 $ (''a'';''b'')'
0.0207669 273536
5 timespacex '''and'' codeinsert("1) 2000 5 $ (''a'';''b'')'
0.0079474 271232
explicit code has a parsing overhead on each call including ranked application,
afaik.
The reason I built the whole thing was a response to a coding challenge:
http://www.reddit.com/r/dailyprogrammer/comments/2e2v28/8202014_challenge_176_hard_spreadsheet_developer/
It seems useful for building selectors concisely which is why I didn't follow
the challenge's directions to the letter.
Also, it happens to be the right answer to the question of how to build the
fastest spreadsheet, as long as you ignore "who the hell wants a spreadsheet".
In terms of a J spreadsheet, it can be multidimensional, hold extended numeric
types, hold multidimensional spreadsheets inside cells, can hold formulas as a
built-up script, and the spreadsheet can be effectively i a compiled (to J)
state. All the spreadheet formulas can be represented as dyadic "amendto" (in
this thread), and the formulas input using a 3 column table (spreadsheet) of
assignment ; reference ; function
Though I built it for just the first 2 reasons, I can think of several decent
answers to the why question:
1. displaying a table with a generic UI. whether the UI is html, jhs, the
console spreadsheet you linked or a fancier GUI that still includes a command
line UI. db tables could provide a point and click (or still simpler through
console) for live query refinements of computed fields, group by (use pages),
....
2. A beautiful feature of spreadsheets is code and data in the same
datastructure, and runtime/usertime code modification.
At the bottom of this essay
http://www.jsoftware.com/jwiki/PascalJasmin/dictionary%20settings%20and%20mad%20science%20tree%20functions
is a mixed code/data structure for building a complex case switch applicable
to a routing/load balancer is an example of mixed code and data being operated
on by other code. A dictionary/db table can be thought of as the simplest
spreadsheet. A J locale with code and nouns can be represented as a
dictionary. In the routing example, the spreadsheet is a dictionary of trees
of dictionaries.
tl;dr.... there was a code challenge to parse spreadsheet cell selection
expressions. :P
----- Original Message -----
From: Joe Bogner <[email protected]>
To: Pascal J <[email protected]>
Cc:
Sent: Friday, August 22, 2014 9:06:21 AM
Subject: Re: [Jprogramming] a cool codeinsert adverb
Hi Pascal -
I was comparing implementations and thought more about your
codeinsert. I was wondering if you'd share a bit more of your thought
process so I can learn from it.
In some ways, this explicit definition feels more clear and doesn't
require the use of an adverb
codeinsertJB2 =: 4 : 0
op=:' ',x,' '
> ('(' , ] , op , ')' ,~ [) each/ |. y
)
compared to:
codeinsertJB =: 1 : '[: > (''('' , ] , '' '',m, '' '','')'' ,~ [) each /@:|.'
The performance is negligible too and slightly in favor of the explicit verb
arr =: 1e4 $ ('a';'b')
10 timespacex '''and'' codeinsertJB2 arr'
0.0508719 531584
10 timespacex '''and'' codeinsertJB arr'
0.0521608 530304
Does the adverb approach give something that the verb approach doesn't?
On Fri, Aug 22, 2014 at 7:43 AM, Joe Bogner <[email protected]> wrote:
> sent too soon (sorry for the excess messages)... You could also just
> do this in JS (no need for reverse and reduceRight)... My first was a
> sloppy translation from the J pattern
>
> ['a','b','c','d','e'].reduce(function(x,y) { return '(' + x + ' and '
> + y + ')'})
> ((((a and b) and c) and d) and e)
>
> I find it sometimes interesting to do a compare/contrast between
> languages as a way of deepening my understanding. Apologies for it
> being somewhat off-topic
>
>
>
> On Fri, Aug 22, 2014 at 7:39 AM, Joe Bogner <[email protected]> wrote:
>> As a parallel example in another language, this is how I would do it
>> in javascript:
>>
>> ['a','b','c','d','e'].reverse().reduceRight(function(x,y) { return '('
>> + x + ' and ' + y + ')'})
>> ((((a and b) and c) and d) and e)
>>
>> or as a function:
>>
>> var codeinsert = function(f,arr) {
>> return arr.reverse().reduceRight(function(x,y) { return '(' + x + '
>> ' + f + ' ' + y + ')'})
>> }
>> codeinsert('and', ['a','b','c','d','e'])
>> ((((a and b) and c) and d) and e)
>>
>>
>> On Fri, Aug 22, 2014 at 7:27 AM, Joe Bogner <[email protected]> wrote:
>>> I like the codeinsert adverb. I didn't understand the solution at
>>> first so I thought I'd write my own.
>>>
>>> I started here at a few attempts at first that didn't use "each". I
>>> also quickly realized that I needed to reverse the input
>>>
>>> Attempt #1
>>>> 4 : '''('',y,'' and '',x,'')''' each/ |. ;: 'a b c d e'
>>> ((((a and b) and c) and d) and e)
>>>
>>> Then, I cheated and made that expression tacit with 13 :
>>>
>>> 13 : '''('',y,'' and '',x,'')'''
>>> '(' , ] , ' and ' , ')' ,~ [
>>>
>>> Attempt #2
>>>> ('(' , ] , ' and ' , ')' ,~ [) each/ |. ;: 'a b c d e'
>>> ((((a and b) and c) and d) and e)
>>>
>>> Then I wondered, how could I extract 'and' since that should be an
>>> input, and I've already used my 2 arguments x/y in my dyad. I stopped
>>> and looked at your solution again and realized it was starting to
>>> resemble mine and mine should become an adverb.
>>>
>>> Attempt #3 - turning into an adverb
>>>> ' and ' ( 1 : '[: > (''('' , ] , m , '')'' ,~ [)') each/ |. ;: 'a b c d e'
>>> ((((a and b) and c) and d) and e)
>>>
>>> Attempt #4 - moving the each and / inside the adverb
>>> ' and '( 1 : '[: > (''('' , ] , m , '')'' ,~ [) each /@:|.') ;: 'a b c d e'
>>> ((((a and b) and c) and d) and e)
>>>
>>> Attempt #5 - remove space padding from input M
>>> codeinsertJB =: 1 : '[: > (''('' , ] , '' '',m, '' '','')'' ,~ [) each
>>> /@:|.'
>>> 'and' codeinsertJB ;: 'a b c d e'
>>> ((((a and b) and c) and d) and e)
>>>
>>>
>>> And yours:
>>>
>>> codeinsert =: 1 : '[: > ((''('' , '')'' ,~ [ , '' '' , m , '' '' ,
>>> ])~&.>/)@:|.'
>>> 'and' codeinsert ;: 'a b c d e'
>>> ((((a and b) and c) and d) and e)
>>>
>>> Turns out to be basically the same solution. I enjoyed working through it.
>>>
>>> Regarding the rest of the spreadsheet formulas - can you share how
>>> you're applying it? I can see using the dsl for some simple amends.
>>> Are you using it for a more complex amend or selection example, or did
>>> you add the ability for the complex cases just to see if you can? The
>>> complex amend/select would make me want to first attempt to
>>> restructure the input data
>>>
>>> On Thu, Aug 21, 2014 at 12:01 PM, 'Pascal Jasmin' via Programming
>>> <[email protected]> wrote:
>>>> replying to other topic, because it fixes issues with spreadsheet range
>>>> parsing:
>>>>
>>>>
>>>> codeinsert =: 1 : '[: > ((''('' , '')'' ,~ [ , '' '' , m , '' '' ,
>>>> ])~&.>/)@:|.'
>>>>
>>>> the y argument is a list of boxes where the code will be inserted along
>>>> with parentheses to allow left to right parsing: (result is a string. eval
>>>> will work regardless of whether expression results in noun or function)
>>>>
>>>> 'and' codeinsert ;: 'a b c d e'
>>>> ((((a and b) and c) and d) and e)
>>>>
>>>> Function that strips outer tokens if they are present (default '()')
>>>> stripouter_z_ =:'()'&$: :(}:@:}.@:]^:(-: ({. , {:)))
>>>>
>>>> can work with conjunctions too, and the parens strategy is designed to
>>>> provide some consistency with verbs and conjunctions.
>>>> stripouter '@:' codeinsert cut '+/ +: (-:@*/~)'
>>>> (+/ @: +:) @: (-:@*/~)
>>>>
>>>>
>>>> this allows several simplifications to spreadsheet parser:
>>>>
>>>> parselessand =: ( [: 'less' codeinsert [: 'and' codeinsert each [: '&'&cut
>>>> each '~'&cut)
>>>>
>>>> we can note that this first part of the parser does not care at all what
>>>> the range format is:
>>>>
>>>> parselessand 'A3:C6&D1&B2:B4~F2:F3~G2'
>>>>
>>>> ((((A3:C6 and D1) and B2:B4) less F2:F3) less G2)
>>>> parselessand '2 0:5 2 &0 4&1 1:1 3~1 4:_4 2~5 _1'
>>>> ((((2 0:5 2 and 0 4) and 1 1:1 3) less 1 4:_4 2) less 5 _1)
>>>>
>>>> we can also note that alphanum col format is confusing and useless even
>>>> though the range operator can help with avoiding some parens and
>>>> whitespace.
>>>>
>>>> If we ignore parsing alphanum rowcols then the full parser becomes simply
>>>>
>>>> parseN =: (':';' to ') rplc~ parselessand
>>>> p =: 1 : 'boxopen ". parseN m'
>>>>
>>>> '2 0:5 2 &0 4&1 1:1 3~1 4:4 2~5 _1'p
>>>> ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
>>>> │2 0│2 1│2 2│3 0│3 1│3 2│4 0│4 1│4 2│5 0│5 1│5 2│0 4│1 1│1 2│1 3│
>>>> └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
>>>>
>>>> its also possible to directly use parselessand without the range operator
>>>>
>>>> parselessand '2 0 to 5 2 &0 4&1 1 to 1 3~1 4 to _4 2~5 _1'
>>>> ((((2 0 to 5 2 and 0 4) and 1 1 to 1 3) less 1 4 to _4 2) less 5 _1)
>>>> boxopen ". parselessand '2 0 to 5 2 &0 4&1 1 to 1 3&_4 2 to _4 3~5 _1'
>>>> ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬────┬────┐
>>>> │2 0│2 1│2 2│3 0│3 1│3 2│4 0│4 1│4 2│5 0│5 1│5 2│0 4│1 1│1 2│1 3│_4 2│_4 3│
>>>> └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴────┴────┘
>>>>
>>>> if the less and and operators were remapped to say ? and ! then you could
>>>> also include a fuller range of J code within the string.
>>>>
>>>> ----- Original Message -----
>>>> From: 'Pascal Jasmin' via Programming <[email protected]>
>>>> To: "[email protected]" <[email protected]>
>>>> Cc:
>>>> Sent: Wednesday, August 20, 2014 10:22:40 PM
>>>> Subject: Re: [Jprogramming] dsl for spreadsheet like input selectors
>>>>
>>>> some updates on this, Original definitions:
>>>>
>>>> to2 =: [: <"1 [: ,."0/&>/ [ +&.> [: i.@:>:&.> -~
>>>> to =: 2 : 'm ,@:to2 n'
>>>> and=: ~.@:,&boxopen
>>>> less =: -.&boxopen
>>>>
>>>> a conjunction that takes n (or v"_) as the selection indexes, and then
>>>> uses x if any as the updateto indexes, and assigns to those indexes the
>>>> expression u selected{ y.
>>>>
>>>> amendto_z_ =: 2 : 0
>>>> s=. v"_ y
>>>> (u (s{y)) (s}) y
>>>> :
>>>> s=. v"_ y
>>>> (u (s{y)) (x}) y
>>>> )
>>>>
>>>> doubles left-top 4 cells and sets them to bottom right 4 cells:
>>>> 1 1 to 2 2 +: amendto (0 0 to 1 1) i.3 3
>>>> 0 1 2
>>>> 3 0 2
>>>> 6 6 8
>>>>
>>>>
>>>>
>>>> here are routines to parse spreadsheet format : & ~ . I think I need help
>>>> for the parselessand as it doesn't work for multiple and/less (&~) within
>>>> their frames. This does parse negative indexes though, and you can use
>>>> the and and less keywords in combination with the parser, so the bug has a
>>>> workaround.
>>>>
>>>> linearize
>>>> =: , $~ 1 -.~ $
>>>> parselessand =: [: >@:> [: ('(' , ([: ;`$:@.(1 < #) [) , ') less ' ,
>>>> ])&>/@:(}: ; {:)^:(1 < #) [: linearize@:>L:1^:(1 < #) [: ('(' , ([:
>>>> ;`$:@.(1 < #) [) , ') and ' , ])&>/@:(}: ; {:)^:(1 < #)&.> [: <;._2&.> '&'
>>>> ,~&.> [: <;._2 '~' ,~ ]
>>>>
>>>> that takes care of "compiling" the structure around the cells:
>>>> parselessand'A3:C6&D1~A2:BB3'
>>>> ((A3:C6) and D1) less A2:BB3
>>>>
>>>> splitrowcol=:([: , [: boxopen&> (] <;.1~ [: (1 , }.) 10 >
>>>>'0123456789'&i.)`]@.((1 = L.) *. 2 = #)&.>`(]&.>)@.(2 = #))@:(] <;.1~ [: (1
>>>>, }.) '_' -.@:i: ])
>>>> assidx =: (([: <: 0 ". ]) , (] -@:>:@:]^:('_'= {.@:[) [: fixlet ALPHA i.
>>>>}.^:('_'= {.))@:[) &>/@: splitrowcol
>>>> parseS =: [: ;: inv [: ":@:assidx^:(([: +./ '0123456789' e.~ ]) *. [: +./
>>>> ALPHA e.~ ]) each ( (<,':');<<'to') rplc~ [: ;: ( ':';' : ') rplc~
>>>> parselessand
>>>> final adverb executes compiled sentence and makes sure result is boxed
>>>> p =: 1 : 'boxopen ". parseS m'
>>>>
>>>>
>>>> 'A_0'p +: amendto ('A4'p) 'A4'p (+/%#) amendto ('A1:A3'p) 'A3'p *:
>>>>amendto ('A2'p) 'A2'p 3&* amendto ('A1'p) 3 'A1'p } 5 1 $ _
>>>> 3
>>>> 9
>>>> 81
>>>> 31
>>>> 62
>>>>
>>>> to see more negative indexing,
>>>>
>>>>
>>>> '_A_3:C_1' p
>>>> ┌─────┬────┬────┬────┬─────┬────┬────┬────┬─────┬────┬────┬────┐
>>>> │_4 _1│_4 0│_4 1│_4 2│_3 _1│_3 0│_3 1│_3 2│_2 _1│_2 0│_2 1│_2 2│
>>>> └─────┴────┴────┴────┴─────┴────┴────┴────┴─────┴────┴────┴────┘
>>>>
>>>>
>>>>
>>>> compound statements
>>>> '_A_2:C_1'p less~ '_A_3:C_1&A1:B2' p and 'B1:B3'p
>>>> ┌─────┬────┬────┬────┬───┬───┬───┬───┬───┐
>>>> │_4 _1│_4 0│_4 1│_4 2│0 0│0 1│1 0│1 1│2 1│
>>>> └─────┴────┴────┴────┴───┴───┴───┴───┴───┘
>>>>
>>>> A modification to amendto into an adverb such that indexes can set as part
>>>> of tacit code:
>>>> A dyad where x is either a list of boxes (updated and selected indexes are
>>>> the same), or 2 boxes where each box is updatelist , selectlist
>>>>
>>>> amendtoA_z_ =: 1 : 0
>>>> :
>>>> if. 2=L.x do. 'a s' =. x else. a =. s =. x end.
>>>> (u (s{y)) (a}) y
>>>> )
>>>>
>>>> Boxlink =: boxopen&.>@:,&< NB. joins 2 list of boxed indexes into 2 boxes.
>>>>
>>>>
>>>> different shape assignments: (to2 function allows retrieving selection
>>>> with shape)
>>>> ('A4:C4'p Boxlink 'A1'p to2&> 'C3'p) +/ amendtoA i.4 3
>>>> 0 1 2
>>>> 3 4 5
>>>> 6 7 8
>>>> 9 12 15
>>>>
>>>> sample function that takes any size tables, adds a row and column and
>>>> puts the sum of rows and columns in the new obvious place, and then in the
>>>> bottom right cell, puts the average of the row and column sums:
>>>>
>>>> extendSumAvg =: ((<@:$ Boxlink ((0 ,~ {.@$) ,@:to2 {.@$ , <:@{:@:$) and (0
>>>> , {:@:$) ,@:to2 <:@:{.@:$ , {:@:$) (+/%#) amendtoA (((0 ,~ {.@:$) ,@:to2
>>>> ({., <:@:{:)@:$) Boxlink 0 0 to2 <:@:$) +/ amendtoA (,@:((0 , {:@:$) to2
>>>> (<:@{., {:)@:$) Boxlink 0 0 to2 <:@:$) +/"1 amendtoA 0 ,~ 0 ,.~ ])
>>>>
>>>> ]/each extendSumAvg i.3 2
>>>> ┌─┬─┬─┐
>>>> │0│1│1│
>>>> ├─┼─┼─┤
>>>> │2│3│5│
>>>> ├─┼─┼─┤
>>>> │4│5│9│
>>>> ├─┼─┼─┤
>>>> │6│9│6│
>>>> └─┴─┴─┘
>>>>
>>>> to show off, repeatedly growing spreadsheet 5 times with the algorithm
>>>>
>>>> extendSumAvg^:5 i.3 3
>>>> 0 1 2 3 6 12 24 48
>>>> 3 4 5 12 24 48 96 192
>>>> 6 7 8 21 42 84 168 336
>>>> 9 12 15 12 48 96 192 384
>>>> 18 24 30 48 30 150 300 600
>>>> 36 48 60 96 150 78 468 936
>>>> 72 96 120 192 300 468 208 1456
>>>> 144 192 240 384 600 936 1456 564.571
>>>>
>>>>
>>>>
>>>> ----- Original Message -----
>>>> From: 'Pascal Jasmin' via Programming <[email protected]>
>>>> To: "[email protected]" <[email protected]>
>>>> Cc:
>>>> Sent: Monday, August 18, 2014 5:39:50 PM
>>>> Subject: Re: [Jprogramming] dsl for spreadsheet like input selectors
>>>>
>>>> sorry, mistyped to2
>>>>
>>>> to2
>>>> =: [: <"1 [: ,."0/&>/ [ +&.> [: i.@:>:&.> -~
>>>>
>>>>
>>>> ----- Original Message -----
>>>> From: Brian Schott <[email protected]>
>>>> To: Programming forum <[email protected]>
>>>> Cc:
>>>> Sent: Monday, August 18, 2014 5:32:43 PM
>>>> Subject: Re: [Jprogramming] dsl for spreadsheet like input selectors
>>>>
>>>> I am not getting good results with to2.
>>>> I am playing with the following.
>>>>
>>>> CP=: {@(,&<)
>>>> cross =: [: CP &>/< @:i.@>:"0
>>>> 0 1 -.~&(,&cross) 2 3
>>>> ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
>>>> │0 2│0 3│1 0│1 1│1 2│1 3│2 0│2 1│2 2│2 3│
>>>> └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
>>>>
>>>>
>>>>
>>>> On Mon, Aug 18, 2014 at 4:25 PM, 'Pascal Jasmin' via Programming <
>>>> [email protected]> wrote:
>>>>
>>>>> spreadsheets have a range selection syntax like A1:C3&F4~B2 which means
>>>>> the block range from A1 to C3 with the cell F4 added, and the cell B2
>>>>> removed.
>>>>>
>>>>> Ignoring the letter conversions, here are some useful J functions for
>>>>> building a list of selectors (can be used with both { and }).
>>>>> Conjunctions
>>>>> are used for their power to be higher precedence functions, and reduction
>>>>> of parentheses. Perhaps the only really neat feature of this dsl is the
>>>>> use of conjunctions, as the functions themselves are pretty simple. At
>>>>> the
>>>>> same time, the conjunctions might get in the way if using these functions
>>>>> within forks.
>>>>>
>>>>> the 3 core spreadsheet combiners:
>>>>>
>>>>> to2 =: ( [: <"1 [: ,."0/&>/ [: i.@:>: each -~)
>>>>> to =: 2 : 'm ,@:to2 n'
>>>>> and=: ~.@:,&boxopen
>>>>> less =: -.&boxopen
>>>>
>>>>
>>>>
>>>>>
>>>>>
>>>> --
>>>> (B=)
>>>> ----------------------------------------------------------------------
>>>> For information about J forums see http://www.jsoftware.com/forums.htm
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> ----------------------------------------------------------------------
>>>> For information about J forums see http://www.jsoftware.com/forums.htm
>>>> ----------------------------------------------------------------------
>>>> For information about J forums see http://www.jsoftware.com/forums.htm
>>>> ----------------------------------------------------------------------
>>>> For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm