The opaque one-liner:
using IterTools,ImageInTerminal,Colors;for g in iterated(a->let n=sum(map(t->circshift(a,t),product(-1:1,-1:1)));(a.&(n.==4)).|(n.==3);end,rand(Bool,(99,99)));imshow(map(Gray,g));print("\n\n");end
The legible version where we give everything descriptive names so it's not cryptic and mysterious:
using ImageInTerminal,Colors #the APL demo also uses a library for pretty display
using IterTools #okay *technically* this is a minor cheat
function nextgen(grid)
neighborcount = sum(map((t)->circshift(grid,t), product(-1:1,-1:1)))
return (grid .& (neighborcount .== 4)) .| (neighborcount .== 3)
end
function animate(grid)
for gen in iterated(nextgen, grid)
imshow(map(Gray, gen))
print("\n\n")
sleep(0.05)
end
end
animate(rand(Bool,(100,100)))I still think learning mathematical symbols is better than spelling out mathematical formulas and likewise APL and J to me allow the same power of abstraction; it just takes some effort to learn them. A lot of friction is learning something new.
But the power of abstraction of APL is available to any other language, with the right functions. Most scientific languages come with those functions out of the box, as demonstrated by my 1<->1 translation of 'Life in APL' into Julia above. And APL doesn't give you a bunch of other really useful general-purpose stuff; that's why I term it a 'DSL'. It's a one-trick pony. It's a great trick, but it's ultimately not quite enough. That's why NumPy hasn't replaced pure Python - you still need to get your hands dirty outside the array paradigm from time to time, and APL is very primitive at that. In fact there's nothing to stop anyone from aliasing array-functions to their APL equivalents in any Unicode-aware language, like Julia (oddly, nobody does). What you're left with is a rather basic parser, some odd syntax quirks like arrow assignment, and some ugly imperative flow control.
Are the fancy symbols really worth it?