notePlayer notes octs dur = musicSeq $ (uncurry <$> notes) <*> ((, dur) <$> octs)
Won't make much sense without context, but it's there!
[2]: https://soundcloud.com/a-mathematical-way/not-enough-time-to...
notePlayer notes octs dur = musicSeq $ (uncurry <$> notes) <*> ((, dur) <$> octs)
Won't make much sense without context, but it's there!
[2]: https://soundcloud.com/a-mathematical-way/not-enough-time-to...
notePlayer notes octs dur = musicSeq $ notes <*> octs <*> pure dur
Coincidentally, this might be a testament of the power of parametric polymorphism and equational 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.
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.
Purity's power is that beautiful meaningless changes are safe.