
Game of Life in one Ruby statement inspired by APL - todsacerdoti
https://zverok.github.io/blog/2020-05-16-ruby-as-apl.html
======
faizshah
I wish Ruby was “the data science language” tbh. Ruby has some of the most
beautiful and concise idioms of any language. I remember the first time I
learned procs, blocks and lambdas my mind was blown with how elegant ruby
solutions to problems can be. It’s a shame I have to use python instead.

~~~
burlesona
Agreed. Ruby is more consistent than Python IMO, and has especially beautiful
semantics for the list processing.

It’s interesting, Ruby can be a bit more performant too. I discovered this
when I taught some ML stuff to a ruby group, and converted some Q Learning
programs and maze navigating stuff from Python to Ruby, and was surprised to
see the Ruby version run around 1.3-1.8x faster depending on what the code was
doing. It’s not enough difference to really matter, but it just reinforced my
“aww shucks” feeling that Ruby could have served that ecosystem very well.

~~~
7thaccount
All the performance benchmarks I've seen over the years have shown Python to
be significantly faster than Ruby. Keep in mind it doesn't matter a whole lot
as the scientific stuff calls out to C or Fortran anyway.

------
burke
Here’s a version of Game if Life I wrote in ruby ages ago that was inspired by
APL in a, uh, different way:
[https://gist.github.com/burke/1428424](https://gist.github.com/burke/1428424)

~~~
kragen
This is terrible and wonderful. Thank you. I feel truly blessed to have seen
this. It won't open a gate, will it?

~~~
burke
Never has for me but YMMV. Maybe a salt circle just out of an abundance of
caution.

------
kragen
While I think this is helpful as a way to understand the APL original, the
title is sort of false advertising.

It's sort of not one Ruby statement if it starts with

    
    
        require 'apl'
    

and uses some APL::Ary class that, as far as I can tell, isn't in the Ruby
standard library. I was hoping to see how Enumerable enabled this, not how you
can implement APL in some arbitrarily large amount of Ruby code offscreen,
because of course you can do that.

~~~
semanticist
The APL module is in the `lib` directory of the repo holding the code, you can
see the implementation there.

It wouldn't be that bad to pull all the library code out into the 'main'
command, but it would lose the 'single statement' impact and probably be
harder for people to follow along with.

~~~
kragen
Aha, I thought maybe it was an existing gem.

Anyway, I think it probably _should_ lose the "single statement" impact,
because in that context it's just misdirection, magician's patter. Yes, a
single Ruby statement can invoke an arbitrarily complex piece of library code
written for the article, but that doesn't tell you anything interesting about
either Ruby or how to use it — the same is true of any programming language
that supports programs in multiple modules, even assembly language:

    
    
        start: CALLQ play_life
    

Now, the particular statement in question is considerably more illuminating
than that, but presumably if you wanted to do almost anything else in an
APLish style in Ruby, you'd probably have to implement more operations in
apl.rb. I see that it doesn't include, for example, scan, slicing, or any
broadcasting operations other than +, &, and |. (*, -, and / are missing, for
example.)

I mean, I've certainly written worse implementations of APLish operations. You
could certainly extend apl.rb into something practically useful. I just don't
think it's fair to put four pages of code in one file and then direct people's
attention to the single statement in another file that invokes it.

~~~
tinco
That "ofcourse" you can implement Game of Life in one statement if you
implement (parts of) the standard library of APL is not obvious to many
people. The point of the blog is to introduce people to the concepts of APL,
not to pitch some innovation.

As a Ruby programmer who already knew about APL, I thought the title exactly
matched the article. I was pleasantly surprised at how clean he designed the
apl library, and the nice explanations.

~~~
kragen
Oh, I guess that's true. I remember when I was a kid I didn't have any idea
how the BASIC interpreter worked either, and I didn't have any idea about how
to build a tower of abstractions. So surely there are Ruby programmers who
hadn't thought of trying to implement APL primitives in Ruby (especially if
they haven't seen NArray.) Still, Ruby is pretty big on building embedded
DSLs, so I'd think novice programmers learning Ruby would encounter that idea
pretty early on.

But there's always today's lucky ten thousand! I hope I didn't make any of
them feel condescended to. Welcome to the wonderful world of implicitly
parallel vector operations!

------
abrudz
How does the performance stack up against APL's 1000 generations of a
1000-by-1000 world in under a second?
[https://aplwiki.com/wiki/John_Scholes%27_Conway%27s_Game_of_...](https://aplwiki.com/wiki/John_Scholes%27_Conway%27s_Game_of_Life#Performance)

------
7thaccount
This is a pretty nifty piece of work. Not really a oneliner if it requires a
1/4 page of code, but I'll let it slide :)

I do like the concept of keeping I/O in a more traditional language and the
matrix/array code in something closer to APL.

~~~
samatman
This is why it says one statement, not one line.

I've written single-statement argument parsers that take up most of a page of
code.

I like this because I've barely written more Ruby than APL (none of the
latter) but it's perfectly legible to me.

I respect the APL family and think the notation-as-a-tool-of-thought camp has
a lot going for it. I'm just illiterate in that language.

------
burlesona
This is very cool, and as an interesting side effect, it helped me understand
exactly what's going on in the "famous" APL code. Well done!

~~~
dan-robertson
Well mostly but the explanation forgets to mention the ravel (comma/array
flatten) operator in the comment section and the article doesn’t really
explain the inner product bit (matrix multiplication in the rig of or and
and), which I think is more confusing. In particular the 1 ω part.

~~~
zverok
(author here) I noticed the thing about flatten an hour ago and fixed it
(somehow thought +/, is "reduce 2 times", then understood it is flatten +
reduce, and my lib already had flatten, so it was easy to fix). As for "inner
product", I just haven't found suitable Ruby metaphor and fell back to
zip+reduce, which seems to be equivalent.

------
submeta
Wow, this is beautiful! Thanks for sharing.

Btw I love that Ruby methods return a value, so method chaining works so good.
That‘s something I appreciate in Mathematica‘s postfix notation (for instance
`x // Sin`), and also what I love in R‘s pipe operator, Unix‘s pipe. So many
other languages like Elixir offer it. Unfortunately this does not work out-of-
the box in my beloved Python.

~~~
dan-robertson
Do you mean that ruby methods _are_ values and so they can be passed to
functions?

~~~
submeta
They _return_ a value, like functions.

~~~
rexpop
Is this not normal?

~~~
submeta
No, it is not. Python's `my_list.sort()` will sort the list in-place without
returning the sorted list. If I wanted to have a return value (without
changing the original list), I'd have to use `sorted(my_list)`.

------
ngcc_hk
Quite a good intro to ruby. Wonder can one do one line lisp as well.

------
SydneyPumpkin
Why is Ruby so popular here at HackerNews, I just don't get it!

~~~
dang
Off-topic, sorry, but could you please stop creating accounts for every few
comments you post? We ban accounts that do that. This is in the site
guidelines:
[https://news.ycombinator.com/newsguidelines.html](https://news.ycombinator.com/newsguidelines.html).

You needn't use your real name of course, but for HN to be a community, users
need some identity for others to relate to. Otherwise we may as well have no
usernames and no community, and that would be a different kind of forum.
[https://hn.algolia.com/?query=by:dang%20community%20identity...](https://hn.algolia.com/?query=by:dang%20community%20identity&sort=byDate&dateRange=all&type=comment&storyText=false&prefix&page=0)

~~~
SydneyPumpkin
got it

