Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I 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 and 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.


Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: