Hacker News new | ask | show | jobs
by BucketSort 2472 days ago
It's just mind boggling how universal these concepts are and how they show up in surprising ways. As a recent example, I've been learning the basics of composing music in Haskell with Euterpea[1] and wanted to make a function which played several notes over a list of octaves to make chords. It turns out the applicative operator was exactly the function I need to do this! It would be hard to go into the details in just a little blurb here... but here is a piece I made with with it[2]. And here's the line of code with the applicative operator:

notePlayer notes octs dur = musicSeq $ (uncurry <$> notes) <*> ((, dur) <$> octs)

Won't make much sense without context, but it's there!

[1]: http://www.euterpea.com/

[2]: https://soundcloud.com/a-mathematical-way/not-enough-time-to...

1 comments

I have never heard of Euterpea, nor have I seen the rest of your code, but I suggest you refactor your slightly convoluted code like this:

    notePlayer notes octs dur = musicSeq $ notes <*> octs <*> pure dur
Coincidentally, this might be a testament of the power of parametric polymorphism and equational reasoning.
My favorite part about Haskell is how you can know literally nothing about the domain and make meaningful changes to programs regardless thanks to local reasoning.

That's really one power of functor/applicative/monad - if you understand their interfaces, you can work with new unfamiliar types that have these instances without much effort at all.

It's amazing. No one could ever do something like this with an imperative language!
Nobody ever said that :)

Although abstracting over this stuff isn't possible in any imperative language unless Scala or maybe advanced C++ template count. But that isn't due to their imperative nature exactly.

But local reasoning is very hard to count on in most other languages - that's for sure. It's easier to just run a VM in your head.

It's literally a meaningless change! :-) All refractorings at meaningless changes, by definition and design.

Purity's power is that beautiful meaningless changes are safe.

Amazing, thanks! It always amazes me how natural Haskell is for some people. Some seem to see the simplest solution with so little effort while I still struggle with almost embarrassingly simple things. I wish I would have picked up Haskell as my first language, instead my mind was poisoned by C...
I haven't figured out whether the C I learned was poison. I often wish I could intuit Haskell without translating everything to imperative in my head, because of how cleanly many complex things can be expressed. On the other hand, pretty much everything I program has some rough kind of performance constraint in practice and I appreciate how directly I can read the performance characteristics of an imperative program from its control flow.
Definitely learning Haskell as the first language can make it easier to get used to things, but I don't generally agree with C as "poisonous" to one's mind. My last big project written in C was writing a hypervisor, and honestly using C in this context is rather appropriate.