6 ms·
Algebraic Effects in Practice with Flix
- siscia 1y agoThis is absolutely neat.
- artemonster 1y ago"The only one that I know of besides Flix is Unison." huh? Koka, Effekt
- marvinborner 1y agoRegarding Effekt, here's an interactive introduction on how to use its effect system: https://effekt-lang.org/tour/effects https://effekt-lang.org/tour/effects Other pages also contain some more advanced details and casestudies on effect handling
- saviorand 1y agoKoka, Effekt and 4 other research languages are mentioned earlier in the article though? This talks about practical languages, not research-only
- artemonster 1y agoI really want effects to shine and thrive, but since this is a very academic topic, only academic people engage with the research and it comes with academic pedantism, perfectionist worldview, strange attraction to beautiful consistency, etc. This automatically places effect research FAR from any practicality and grounded realism. 2 points, as examples: 1. Ever tried adding a simple print statement for debugging purposes while coding in effectful lang? compiler: "NNNOOOOO!!!! THIS IS AN ERROR; I WILL NEVER COMPILE THIS NONSENSE YOU __MUST__ SPECIFY CONSOLE EFFECT WAAARGHH!11" 2. multi-resumable stacks. how many times you really want to implement custom backtracking for multi resumable computations? this is such an obscure nonsensical use case that is hard to nearly impossible to solve efficiently, but everyone wants to support it. supporting this adds enormous complexity and kills any potential for performance. WHYYYYYYYYY. and yet they focus on this as a holy grail feature but whever there is a showcase they use synthetic "choice" example, lol.
- Warwolt 1y agoTo be fair, presumably debug printig could be "escaped" from the effect type checking if the designer of an effect system would want it. For instance, debug printig in Haskell completely sidesteps the need for the IO Monad and just prints in whatever context
- artemonster 1y agoyeah, most times its solved by side-stepping the strict type system and making an exception for debug prints. but this is not a real practical solution, this is a stupid workaround born from overinsistence on "beautiful" design choices.
- thfuran 1y agoIt seems to me like a pragmatic compromise and very much a real solution. What would you consider a real solution that isn’t overinsisting on beautiful design choices?
- artemonster 1y agoputting strong static type system into optional compiler pass. yes, I know this may be null is some cases, let me run my program for now, I know what I am doing. yes, there are unhandled effects or wrong signature, just let me run my test. yes, that type is too generic, i will fix it later, let me run my god damn program.
- noelwelsh 1y agoThis puts a lot of extra conditions on the runtime; you basically have to implement a "dynamically typed" runtime like Javascript. In doing so you lose a lot of performance. Google have invested something like a century of man-hours into V8 and on typical benchmarks the performance is about half of Java's, which in turn is typically about half of C / Rust's performance. That's a pretty big compromise for some.
- mrkeen 1y ago> Solving the “what color is your function” problem. Eh. I currently use monads for my effects, and am open to the idea of language-based effects. But this isn't a solution to the colour problem - it is the colour problem. The compiler stops you accidentally calling red from blue. If you want to do it deliberately, you change the caller from blue to red.
- epolanski 1y agoThis depends on the implementation. In effect typescript land, synchronous and asynchronous code is treated equally as soon as it's lifted in an effect.
- gf000 1y agoOne important thing that languages with algebraic types can usually do and most others can't is being generic in this "colorness" - precisely because this is the color problem they are solving. So they can e.g. have a `map` function that can take a pure lambda, or an effectful one, and based on that itself will become pure or the given effect. Colors will stop being "infectious" without limits, you can now better barrier their reach.
- voat 1y agoThe algebraic effect handler pattern is a much simpler mental model than monads. And is transferrable to other languages pretty easily. See something like https://github.com/doeixd/effectively https://github.com/doeixd/effectively in Typescript
- epolanski 1y ago1. The effect data type admits an instance of monad, like arrays or option or result. Not sure why would you put those in competition, an effect is a supercharged ReaderResult. The only differences are in naming choices, traverse being called foreach, flat map being called "and then", etc. 2. There is a much more popular and robust implementation of effects for Typescript: https://effect.website/ https://effect.website/
- naasking 1y ago> The only differences are in naming choices Naming choices matter, as does syntax.
- mrkeen 1y agoI use effects to make guarantees about what the code will and won't do. When Option was retrofitted onto Java, the NPEs didn't disappear. We got Options that could be null, but more importantly, devs (and the standard library) continued to use null liberally. We never ended up at the tautological goal of "if I have a Person, then I have a Person". I am equally skeptical of bolting on effect systems after the fact. Even if one of these effect systems becomes 'the main one' and starts showing up in standard libraries, we'll still end up with declared-effectful code and undeclared-effectful code, but will again fall short of the goal, declared-effectful code.
- IshKebab 1y agoI agree, this seems like something where it really needs to be natively supported in the language from day one to work properly.
- sidkshatriya 1y ago
- ZeljkoS 1y agoOCaml got experimental algebraic effects in version 5.0 (December 2022). Here is a tutorial: https://github.com/tanelso2/ocaml-effects-tutorial https://github.com/tanelso2/ocaml-effects-tutorial Also from the tutorial: "Unlike Eff, Koka, Links, and other languages that support effect handlers, effects in Multicore OCaml are unchecked currently. A program that does not handle a performed effect fails with a runtime error."
- tanelso2 1y agoI upstreamed all of my changes so really we should be linking to https://github.com/ocaml-multicore/ocaml-effects-tutorial https://github.com/ocaml-multicore/ocaml-effects-tutorial instead of my repo.
- nkrisc 1y agoFor anyone using a dark theme with their browser or OS, the string constants actually have interpolation syntax in them. It's just black, on a black background. For example, I thought it was strange their error message was: "Error: " Turns out its actually: "Error: ${msg}"
- vips7L 1y agoMaybe I’m not getting it, but isn’t this just interfaces and implementations from the OO world? For example their movie one is: interface MovieApi { List<Movie> getPopularMovies(); } What are effects providing over this?
- iroddis 1y agoI wasn’t aware of effects until I read the article, but I like the idea. The example you have is just an interface. Effects work a bit like boundary hooks. A pure function only works on things internal to its scope, and so it has no effects. An impure function might affect things outside of its scope, and may want to allow the caller to hook when those effects occur. Think a function that uses the gpu. That’s a side effect, and the function should be decorated to reflect that. I’m guessing some languages would allow for checking to ensure that any induced effects are correctly noted and advertised so that the system as a whole can be more easily reasoned about.
- abeppu 1y agoI _think_ the distinction is that the interface tells you what MovieAPI _does_, but this system also tracks what are contextual requirements to do that thing. So when they write their version of the MovieAPI that calls out to an existing web api, they have to write `\ {Net, IO}` on the main method that uses them. When they write their test that uses a canned recommendation, they can just write `\ {IO}`, and they have a complicated pile of test logic and confirm just at a glance at the top-level signature that no network calls are made when the test runs. So in java, you could write two distinct classes implementing the MovieApi interface as you defined it, one of which calls out to the web and one which doesn't, and nothing about the type indicates that difference. If you accidentally used the wrong class, your tests could make a network call and you might never notice, because you would not have tracked that effect. For someone with a java background, it's really helpful to make the analogy to Checked Exceptions, which let us propagate information about what kind of handler must be required contextually.
- alethic 1y agoThe checked exceptions analogy is a good one. Thinking of effect handlers as resumable checked exceptions with some syntactic sugar is very accurate. For someone with a Haskell background, thinking about them as "dependency injection" is also helpful (and these notions are equivalent!) but for the Java heads out there, yeah, resumable checked exceptions provides a really good mental model for what effect handlers are doing with the call stack in the general case.
- msk-lywenn 1y agoAre algebraic effects a recreation of common lisp’s condition system?
- alethic 1y agoThey are similar, but effect handlers are more powerful and more amenable to typing. https://lobste.rs/s/q8lz7a/what_s_condition_system_why_do_you_want_one#c_pw7da1 https://lobste.rs/s/q8lz7a/what_s_condition_system_why_do_yo...
- keeganpoppen 1y agowait, associated types are amazing! i have spent more time than is healthy goofing around with doing more things than is probably sane via metaclasses, and this concept would actually make life SO much cleaner… i was already predisposed to liking this post because i feel strongly that algebraic effects (and delimited continuations) are amazing and being slept on, but having poked around the docs and blog a bit i am beyond impressed. baasically every “choice” made with this project is one that i either agree with or i’ve never seen before and is quite clever. for example, putting polls in the middle of blog posts to ask the reader what kinds of things would be most relevant for them to touch on in future posts. maybe others have done it before— i don’t know— but what a great way to run a programming language project, where i can only imagine that trying to get in the minds of actual or prospective users is one of the hardest tasks— probably more so than the implementation and development of the language itself! will be watching this project for sure!
- keeganpoppen 1y agoin that same vein, “nothing runs before main” is actually an extremely based take. i suppose this is another take informed by my python (mis-)adventures, but it is so unfortunate that you don’t have just a liiittle more flexibility in terms of the order that code, imports, etc. are evaluated. it is hard for me to give a concise answer as to why i felt this pain, but it is an idea that immediately feels like respite, and gives programmers more leverage / lattitude in making libraries / other code simpler and ergonomic.
- quantummagic 1y agoThere are some parallels with Zig's current move toward an IO-object, and requiring it to be passed to any function that wants to do IO (so that it can call methods on that object). Admittedly, it's a more limited and less elegant implementation, but it's a small step in this direction.
- LudwigNagasena 1y agoI think it is a cool feature, but I see some practical issues. For me, encapsulation is a feature. I would like to see that a function uses a network call deep down, but only in a static analysis sort of way. So I don't want to mark something as potentially using a network until it actually uses it. And at the same time I wouldn't want to change every effect of every intermediate function just because I made something use an LLM or Redis cache. It also seems that cross-cutting components such as observability instruments are just going to contaminate all functions with their need for memory, network, io, files, clock, locale, reflection, etc.
- kephasp 1y agoFirst, you can write a function that's generic on the effects used, so you could write use it in a way that calls an LLM and use it elsewhere in a way that cannot, with the same logic. But I see the need to change the code as a good thing when it is necessary: I don't want a dependency, inside or outside my codebase, to suddenly add network calls without me knowing it. Same goes for code that was pure and has become stateful. Not knowing this kind of fundamental change is a recipe for a nightmare. It should be especially apparent with the recent supply chain attacks.
- LudwigNagasena 1y agoIn the real world you usually want to extend datatypes and provide new implementations without recompiling let alone rewriting old code (The so called expression problem). This is the raison d'être of complex DI and IoC enterprise patterns and various monkey patching techniques. I am not sure how flexible the effect approach is. It took decades before static typing became painless enough for rapid agile development. Properly typed DI with safeguards sounds wonderful, but can algebraic effects actually deliver that?