3 ms·
I'm curious if you would still think of token count as a useful metric if the Ruby version turns out to be twice the size of the equivalent code in J or K due t
by reinhardt 15y ago
I'm curious if you would still think of token count as a useful metric if the Ruby version turns out to be twice the size of the equivalent code in J or K due to "redundant" "noise" tokens. Programs should be written for people to read, and only incidentally for machines to execute.
- kragen 15y agoI do think it's a useful metric, and I am often tempted by the low token count of Forth and APL dialects like J and K, but much of the APL reduction in code size comes not from token-count reduction, but from token-length reduction, which is much less praiseworthy in my book. Here's Life in Dyalog APL, from http://dfns.dyalog.com/c_life.htm http://dfns.dyalog.com/c_life.htm and http://news.ycombinator.com/item?id=1041500 http://news.ycombinator.com/item?id=1041500: life←{ ⍝ John Conway's "Game of Life". ↑1 ⍵∨.^3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵ ⍝ Expression for next generation. } Unfortunately, my APL is pretty rusty, and Dyalog has added some major extensions to the language, so I'm not quite sure what that means, in particular the juxtaposition of 1 and ⍵ toward the beginning. I think it parses as vertically_rolled = outerproduct(⌽, [-1, 0, 1], ⊂(⍵)) horizontally_rolled = outerproduct(⊖, [-1, 0, 1], vertically_rolled) neighbor_counts = sum(ravel(horizontally_rolled)) ↑(⍵(1, innerproduct(and, or, ⍵, [3, 4] == neighbor_counts))) but I'm not even sure of that. The Life rule (which is pretty optimal for being expressed in APL, given its array orientation) is slightly simpler than the Wireworld rule: def run_wireworld_rule old_cells = @cells @cells = fresh_cells each_coord do |x,y| # This could be optimized somewhat by only recalculating # the neighbors of dirty cells. case old_cells[x][y] when :electron_head set x, y, :electron_tail when :electron_tail set x, y, :wire when :empty # do nothing; fresh_cells are all :empty when :wire case electron_head_count old_cells, x, y when 1, 2 set x, y, :electron_head else # Don’t call `set` in this case so as not to mark # the cell dirty for redrawing. @cells[x][y] = :wire end end end end # This could perhaps be optimized somewhat with a sum table. def electron_head_count(cells, base_x, base_y) count = 0 ([0, base_x-1].max..[base_x+1, @nx-1].min).each do |x| ([0, base_y-1].max..[base_y+1, @ny-1].min).each do |y| count += 1 if cells[x][y] == :electron_head end end return count end def each_coord (0..@nx-1).each do |x| (0..@ny-1).each do |y| yield x, y end end end The APL people claim that their programs are more readable because they're shorter, but I'm not sure how much I believe their claim. It's certainly true that other kinds of mathematical notation benefit enormously from brevity and consistency that permits mechanical manipulation, and I don't see why algorithms should be different, but empirically I have a lot less trouble with Ruby or Python (or even C) than with plain-English descriptions of mathematical equations.