spell-music / csound-expression

Haskell Framework for Electronic Music
320 stars 31 forks source link

SE could be Applicative only (not Monad)? #52

Closed jwaldmann closed 5 years ago

jwaldmann commented 5 years ago

Hi. While trying to understand SE, I was thinking - this should work without the Monad instance. Applicative is enough? See https://www.imn.htwk-leipzig.de/~waldmann/etc/untutorial/ce/#what-can-we-do-with-results-of-actions

anton-k commented 5 years ago

This is not enough. The example is delay buffers, or writing to files. It can not be expressed in applicative

jwaldmann commented 5 years ago

Writing a file is fine, since the result is always (). Can we read a file?

I am still not sure about the relation between IO and SE. Can we embed IO in SE? (I don't see how.) E.g., is there some way to execute an IO action each time some event happens (e.g., on metro 1)?

I was thinking that this cannot not work, since event handling is done in the back-end, and csound cannot call back into the front-end (the Haskell program)? But perhaps I am mistaken.

anton-k commented 5 years ago

We can not embed IO, since CE is a text generator, it does not execute anything... SE is kind of "like" IO inside Csound code.

jwaldmann commented 5 years ago

OK, then we are thinking the same about IO/SE.

But then, do you agree that with (>>=) :: SE a -> (a -> SE b) -> SE b, computing a >>= f requires that the result of action a (executed in the back-end) is transported to the front-end, since the Haskell function f needs to be applied? My theory is that since this cannot happen, all the usages of >>= could be rewritten to use (<*>) instead.

Of course, I am not saying that this should actually be done, as this would touch a lot of code. It is just for clarifying my thinking.

anton-k commented 5 years ago

Applicative is really no enough. There are cases like:

anton-k commented 5 years ago

There is no frontend and backend. No data transition or interaction. it's just text generator Bind is generic in it's types but at the end of the day the last function should return something from type class RenderCsd to be useful.

This is intetresting trick to keep variables free from constraints. It allows us to use standard haskell type classes like Monad