Comment by thristian

20 hours ago

APL and K are still pretty daunting, but I've recently been dabbling in Lil[1], which is something like a cross between K and Lua. I can fall back on regular procedural code when I need to, but I appreciate being able to do things like:

    127 * sin (range sample_rate)*2*pi*freq_hz/sample_rate

This produces one second audio-clip of a "freq_hz" sine-wave, at the given sample-rate. The "range sample_rate" produces a list of integers from 0 to sample_rate, and all the other multiplications and divisions vectorise to apply to every item in the list. Even the "sin" operator transparently works on a list.

It also took me a little while to get used to the operator precedence (always right-to-left, no matter what), but it does indeed make expressions (and the compiler) simpler. The other thing that impresses me is being able to say:

    maximum:if x > y x else y end

...without grouping symbols around the condition or the statements. Well, I guess "end" is kind of a grouping symbol, but the language feels very clean and concise and fluent.

[1]: https://beyondloom.com/decker/lil.html

I assume this is the same as this?

  # python
  [127 * sin(x * tau * freq / samplerate) for x in range(samplerate)]

  • For that matter,

      # python
      from numpy import sin, arange, pi
      127 * sin(arange(samplerate) * 2 * pi * freq / samplerate)

  • Pretty much, yeah! The difference is that in Python the function that calculates a single value looks like:

        foo(x)
    

    ...while the function that calculates a batch of values looks like:

        [foo(x) for x in somelist]
    

    Meanwhile in Lil (and I'd guess APL and K), the one function works in both situations.

    You can get some nice speed-ups in Python by pushing iteration into a list comprehension, because it's more specialised in the byte-code than a for loop. It's a lot easier in Lil, since it often Just Works.