-
Notifications
You must be signed in to change notification settings - Fork 11
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
Difference to effectful #2
Comments
Hi @maralorn, thank you for your interest in Bluefin and your good questions! I suspect similar questions are going to come up a lot, so it's helpful for me to practice my answers.
I think in practice there won't be so many function parameters. Users will bundle parameters that are commonly used together into product types (just like we do with normal function parameters).
I'm not sure it defeats the purpose. I think the ideal situation would be to have the explicit Bluefin style and the implicit effectful style available in the same library, if the cost of switching between the styles can be kept low. I think it's plausible that an effectful style API could be layered on Bluefin. I think it's less likely that Bluefin style API could be layered on top of effectful (because it would be hard to convince effectful to have two effects of the same type in the same operation) but perhaps I've missed something.
I haven't benchmarked, but I doubt there's a performance problem passing handles around. Passing arguments is one of the cheapest things you can do, requiring no allocation. It's also the kind of thing that's very easy to eliminate with inlining. I certainly don't see how it can be more expensive than the closest alternative: passing arguments implicitly in a class constraint.
I don't understand the connection between knowing the handlers at compile time and making them type level arguments. Type level arguments need not be known at compile time! In any case, I have tried something similar but it seemed less ergonomic to me. You need There is an another alternative approach to implement an effectful style API on top of Bluefin, but I haven't fully worked it out yet.
Yes, I guess you could do that. Then indeed GHC can infer the types (but, to reiterate, you need to apply the type applications explicitly at each call site, so it probably doesn't help you do what you want.) The alternative approach could infer the types if they are unique ...
The alternative approach would be quite similar to effectful. In fact it would be so similar that it would be Bluefin redundant, unless you want to mix-and-match Bluefin and effectful styles, as I described above. I don't think Bluefin is more "potent" in terms of effects that can be implemented. Despite saying in Bluefin's introduction that I don't know how to support The big difference is that Bluefin makes effect disambiguation a non-issue. Already, having to disambiguate effects by type is a big ergonomic drag (effectful's author suggests Because Bluefin has no difficulties with disambiguation (the "cost has already been paid" by making handles explicit) it means it can be extremely flexible in other ways, for example To conclude this section I'll point out that I'm not convinced that explicit effect handles are actually a cost, in ergonomic terms. After using them for a while I actually prefer them to implicitly passed effects.
You're welcome. I'm happy to help. Please do continue to ask any questions you may have or share any comments. |
I guess I’ll just try it out and see how it goes. |
Great, please report your feedback! |
I've been thinking about this area for a while too so thanks for starting this discussion!
Under the hood, effectful also passes handles around, since effectful's monad is a In bluefin, there is no implicit array/record of handlers. All of the handler passing is explicit. A simple illustrative situation is two handlers on top of a call to the outer handler.
A remark on ergonomics: if the effects For some related literature, Bluefin is similar to the named handlers of the Koka language, a feature presented in the paper "First-class names for effect handlers". Koka supports both unnamed handlers and named handlers, and uses the same rank-2 type trick as bluefin to keep track of the scope of names/handles. Named handlers are a form of capability, and there's work exploring that connection implemented in the Effekt language. |
Okay, I will just continue abusing this thread for my questions. Please feel free to redirect me, e.g. to the Haskell discourse or anywhere else.
|
For adapting an existing mtl-style effect, have a look at the I believe that "dynamic effects" as they are called in effectful are those where the interface of the effect is encoded as a (G)ADT. For example, the
Then the type of "handle"/"environment" that is being passed around can be exactly the handlers of those operations
You now have all the freedom to give new interpretations to An additional "dynamic" ability that you get in effectful is to override an existing handler using
then the equivalent of |
Thank you @Lysxia for your extensive example. That makes a lot of sense to me. Sadly I underspecified the problem I am trying to solve a bit. In your example |
It's fine by me to continue here.
I don't think I understand clearly enough what you're asking. I understand that you are using a library that has a function of this type (and the reflex example seems to confirm that). Are you asking how to run a Bluefin program with this handler? I guess not, because the higher-order argument to |
I was hoping to use runMyMonad to define and run an effect with bluefin. But I assume that won’t be possible without introspecting what MyMonad really does and possibly replacing/reimplementing it. In the end I would take any solution which would make reflex compatible with bluefin or effectful. The effectful documentation made me hope that this might be possible (because it gives so many examples of being compatible with a lot of stuff) but I currently don’t see how this is achievable. |
You won't be able to use On the other hand it's likely there are either primitives or internal Reflex functions that would allow you to do what you want. It looks like |
Yeah, I realize that I will really need to dig into that stack to figure out if I can mirror it. Another thought which came to mind: Have you thought about using Bluefin with ImplicitParameters for the handles? I haven’t used it and it is apparently not a very popular extension but it might be particularly useful for this? |
Yeah, it doesn't seem to work terribly well: |
On 2024-04-03 05:44, tomjaguarpaw wrote:
Yeah, it doesn't seem to work terribly well:
d55a7c9
Aww, sad.
|
Just fyi, I tried to play around with this a bit and I figured out how to define and run a Reflex effect. Its just the first step of the rather intricate transformer stack used in reflex, but with the POC working I think it will be possible. You can find my example here: https://code.maralorn.de/maralorn/config/src/commit/646fb8833c181fd16a3c486b8a876c85f861f654/packages/kass/lib/Bluefin/Reflex.hs |
Thanks to your prompting I wrote up an example of how to do dynamic effects with Blufin. It's really simple! (Although it could do with some ergonomics massaging.) You basically just create a record of operations, and then define them by delegating to other handlers. bluefin/bluefin-internal/src/Bluefin/Internal/Examples.hs Lines 267 to 325 in b4a4853
|
Nice! Just the `weakenEff has` feels a bit unergonomic. Also I realize how
"methody" or just "namespacy" this can feel if you do `fs.readFile`. That’s
pretty neat.
Generally at some point in the future a guide to the different effects
manipulation operators like `weakenEff`, `mergeEff` would be awesome. But maybe
best to wait a bit to discover which patterns are most common and useful.
…On 2024-04-04 06:18, tomjaguarpaw wrote:
Thanks to your prompting I wrote up an example of how to do dynamic effects with Blufin. It's really simple! (Although it could do with some ergonomics massaging.) You basically just create a record of operations, and then define them by delegating to other handlers.
https://github.com/tomjaguarpaw/bluefin/blob/b4a4853ca9e7ccc5aaa547465880a3b7aaf580c3/bluefin-internal/src/Bluefin/Internal/Examples.hs#L267-L325
--
Reply to this email directly or view it on GitHub:
#2 (comment)
You are receiving this because you were mentioned.
Message ID: ***@***.***>
|
Yeah exactly, it is unergonomic, but I'm sure in time we'll work out an ergonomic way of doing it.
Ah yes! It looks very nice with |
This is a bit nicer now. You only need bluefin/bluefin-internal/src/Bluefin/Internal/Examples.hs Lines 267 to 334 in 333cd61
|
Nice, although the I do have by-the-way now a full blown working reflex effect going and I think I can pull of the same for reflex-dom. I am very pleased. (Progress here: https://code.maralorn.de/maralorn/config/src/branch/main/packages/kass/lib/Bluefin/Reflex.hs) |
Oh, that's just a dummy handler to prove to myself that what I'm doing works in general, not just when there's only one handler.
Great! |
I've got something I'm content with now. Here's a progressive worked example of a "counter" effect, followed by the filesystem effect. I'll write this up as a page in the Haddocks. bluefin/bluefin-internal/src/Bluefin/Internal/Examples.hs Lines 267 to 489 in b5459db
|
Hey there!
I am really intrigued by bluefin, it looks very cool. I am however a bit confused but the design and was hoping to for some clarifying discussion.
The handler as function arguments pattern is indeed very expressive and simple. However it immediately triggers a: So many function parameters, maybe this would be easier with a Reader? Which kinda defeats the purpose. I have a few questions about that:
Thank you for indulging me.
The text was updated successfully, but these errors were encountered: