-
Notifications
You must be signed in to change notification settings - Fork 43
CoroutineT #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CoroutineT #3
Conversation
Having to manually call bounce continuously or risk exploding the stack seems like a tremendous amount of cognitive overhead (requiring great discipline and careful forethought!) as well as distinctly low-level for a language like Purescript. I could understand it if it were, say, 10x faster than With @puffnfresh's Essentially, I'm opposed to decisions and libraries that increase cognitive overhead, increase the ways in which programs can go wrong, and add surprising, inconsistent behavior (you can imagine the Reddit / Hacker News commentary on the need to call Purescript already has great escape hatches when performance is necessary (FFI, Eff). The rest of Purescript should have very low cognitive overhead, reduce the ways in which programs can go wrong, and be consistent, unsurprising, even boring. And that's my 2 cents. :) |
@jdegoes I understand what you're saying, and I'm not necessarily disagreeing with you, but I would say the following:
and you get the same effect. The programmer just has to pick the right monad depending on how much control they want.
and the
where the
I feel like programming with Also, I didn't quite understand your comment about |
This is an unsafe interface because your code will explode if you fail to call "bounce" at the appropriate junctions. Couldn't we expose the same functionality through a sort of "monadic Y combinator", in which a recursive call would automatically perform the bounce? That might provide the (possible) performance benefits of bounce without the externally unsafe API. Also, I am not arguing we make MTL the default way of writing functional code in Purescript. With the effect system, it remains to be seen what will end up becoming "idiomatic functional Purescript". I'm only arguing that with the exception of "
|
@paf31 I'd too be very bothered if Other than that, I think There was some talk about writing a |
As far as I can tell none of the laws are satisfied equationally, even though they might be satisfied operationally. I'm looking at this line https://github.com/purescript-contrib/purescript-trampoline/blob/master/src/Control/Monad/Free.purs#L11 Sorry, I'm not seeing the connection to Here's the gist of my argument: one approach can be expressed in terms of the other, but not the other way around, so why choose the less general approach as the one you want to base the libraries on? As for |
@puffnfresh Indeed, |
I'd also like to say - I don't see any reason why we need to pick just one solution for this. I think both make interesting libraries in their own right, with their own use cases. For making As for |
@paf31 you're right about the monad laws. This makes me very sad. I'll spend a while trying to figure out what we can do. |
@puffnfresh I think you can convince yourself that they hold if you look at it through the lens which identifies Edit: I think it's not a monad because under the isomorphism I haven't proved,
which isn't a monad for the obvious reason. |
One more note: I wrote this mostly to use with And when it comes to beginner adoption, I think that using something like |
Any more thoughts on this? |
Why can't the base monads (such as If a user wants to use a monad transformer, we can assume they are more sophisticated and will be personally responsible for supporting recursion through their choice of base monad or use of something like CoroutineT. But users new to Purescript who just import So my vote would be for: keeping |
I would rather offer both alternatives as separate type synonyms, just because It also seems like a little bit of a shame to have a dependency on Can I not convince you that replacing I feel like if someone starts using monadic recursion and runs into a stack overflow, it should not be surprising. One of the project goals is to stay as close to Javascript semantics as possible, and you don't get surprised in general when Javascript gives a stack overflow due to recursion. How to fix the problem is a different issue, but I think it should require a conscious step to introduce a trampoline. |
I'm currently fixing I'll do the same for my implementation and I can't think of anything other than performance that would then be a problem. I'm happy for PureScript to have JS semantics as long as those semantics don't have a huge cost. I see having to reason about stack safety as a pretty big cost. 💎 |
I agree it might be a big cost, depending on the style of code you're writing. I would just consider any use of If we're just talking about a set of type synonyms, it seems like the easiest solution is just to make a new package which depends on both Edit: Still, none of this really invalidates |
+1 to that. Having to reason about stack safety is substantial cognitive overhead (which in my mind far eclipses the very slight performance penalty that trampolining has in Javascript). Really, there's no such thing as FP without monadic recursion ( I'd much rather people be forced to choose As an aside, that we have to worry about stack safety at all in 2014 is astounding to me. Stack-less VMs are very well-researched. It's a shame they aren't more widespread in mainstream languages. |
@garyb @puffnfresh @jdegoes @joneshf
Moving my
MonadBounce
type class to a branch for more work.This is just for discussion. I'm happy to bin this if we decide that
Gosub
is the way to go, but I would still make a claim that both this andGosub
should have a place in the std lib.I think
Gosub
essentially reifies the closure which happens when usingbounce
, except thatGosub
uses abounce
on every call to>>=
. Also,Gosub
can be implemented in terms ofBounceT
, but not vice versa.evalBounceTEff
is still a victim of the tail call optimizer.