9,242 karma · joined November 30, 2008
Fair enough. But are you responding to something I said? I didn't make that equation.
> The only mystique around algebraic effects is the same mystique there is around monads. I don't know if people have started equating algebraic effects to burritos yet but that's a pretty good way to take something simple and turn it into something confusing.
Ah, are you saying that fundamentally there isn't really much to algebraic effects and they're much simpler than they're made out to be? If so then it perhaps we agree?
https://hackage-content.haskell.org/package/bluefin-0.6.0.0/...
But then at some point it struck me: underlying all these effect systems is just passing stuff in. So I developed my own effect system for Haskell, Bluefin[1], based on capabilities, which means the "capability to perform some effect" is represented by just passing stuff in (that is, a function can do some effect as long as it has been passed the capability to do it).
From this point of view it's hard to understand the excitement over "resume with" and "the part you can’t do with try / catch. It lets us jump back to where we performed the effect, and pass something back to it from the handler". Programming languages have had that feature since forever: a "resumable exception" is a "function call". A dynamically chosen "resumable exception" is the call of a dynamically chosen function, i.e. the argument to a higher order function.
So I don't know why people love the complexity around "algebraic effects". Maybe the mystique has a certain allure. But if you want the most straightforward possible approach I can recommend you try out Bluefin. I'm happy to answer questions on the issue tracker[2].
(Caveat: Bluefin is able to simplify things dramatically by dropping support for "multi-shot" continuations. But mostly you don't want multi-shot continuations.)
EDIT: I was too pessimistic, bazoom42 has noticed this :) https://news.ycombinator.com/item?id=48334067
For the channels you describe above the type signature would look like this
Yield String e1 -> -- stdout
Await String e2 -> -- stdin
Yield String e3 -> -- logging
Network e4 -> -- network
Database e5 -> -- database
FileSystem e6 -> -- file system
Eff es r
Six different capabilities that give you access to six different channels of IO. A "Yield" to which you yield strings to stdout, an "Await" from which you can await strings from stdin, a "Yield" to which you yield log messages, and three abstract effects that allow you to do network, database and file system operations (abstract because I'm not sure exactly how you want them defined, but there's an example of the implementation of a file system effect at https://hackage-content.haskell.org/package/bluefin-0.6.0.0/...).No problem with combining or untangling monads whatsoever. This is the natural conclusion of galaxyLogic's point: instead of dividing your program into two parts (IO and not IO) you divide it into six parts (or maybe 2^6 parts?) according to which fine grained effects you have in scope.
If you (or anyone) has any questions about Bluefin I'm happy to help. Please feel free to ask here or on the issue tracker[3].
[1] https://www.youtube.com/watch?v=RsTuy1jXQ6Y
What's the smallest amount per year you'd say it is obvious that no one needs?
> But almost nobody uses Haskell
Sad, but true
> partly because of poor ergonomics like this!
I'm somewhat dubious that's the reason, partly because I find such ergonomic excellent! Especially those provided by my capability system Bluefin: https://hackage.haskell.org/package/bluefin
In any case, anywhere they’re doing HTTP calls they are already threading IO, so they don’t have to pay an additional cost.
But, flipping the script, if you want to see something like Zig's `Io` interface in Haskell then have a look at my capability system Bluefin, particularly Bluefin.IO. The equivalent of Zig's `Io` is called `IOE` and you can't do IO without it!
https://hackage-content.haskell.org/package/bluefin-0.5.1.0/...
Regarding custom allocators and such, well, that could fit into the same pattern, in principle, since capabilities/regions/lifetimes are pretty much the same pattern. I don't know how one would plug that into Haskell's RTS.
What do you mean, "can't tell"? If I see this in Python
(A)(B)(C)
how do I know which of your 9 it means? Well, I'm a Python programmer so I know that it means A(B)(C)
which is the function A applied to B, which returns a function that gets applied to C. If you're a Haskell programmer you know that it means the same thing.I grant you that it is odd to those who are unfamiliar and it took me quite a while to get used to it, but it's much better to write that way in Haskell when writing programs that use higher-order functions.
l = [1, [2, cat], 4]
There are a few different ways to cook this up. Here's one: {-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Cat = Cat { _age :: Int }
deriving Show
makeLenses ''Cat
data Item
= I Int
| L [Item]
| C Cat
deriving Show
makePrisms ''Item
cat :: Cat
cat = Cat 3
l :: [Item]
l = [I 1, L [I 2, C cat], I 4]
l' :: [Item]
l' = set (ix 1 . _L . ix 1 . _C . age) 9 l
ghci> l'
[I 1,L [I 2,C (Cat {_age = 9})],I 4]> All of these things were later claimed as Agile innovations
Are there some references that demonstrate that? [EDIT: that the signatories thought they were their own innovations]
And if so, is that a bad thing? Ideas are repeatedly rediscovered. This article isn't called "Saying goodbye to Royce, Bell and Thayer", and I'm wondering why not.
That's not true for the way I understand agile. The way I understand it, the testable outcome is whether the principles of the agile manifesto are satisfied
For example, is your highest priority to satisfy the customer through early and continuous delivery of valuable software? If not then you're not agile.
newtype FlippedIO a = MkFlippedIO { runFlippedIO :: IO a }
deriving Functor
instance Applicative FlippedIO where
pure = MkFlippedIO . pure
liftA2 f (MkFlippedIO x) (MkFlippedIO y) =
MkFlippedIO ((flip . liftA2 . flip) f x y)
data Person = Person String String
deriving Show
putStrLnFlipped = MkFlippedIO . putStrLn
getLineFlipped = MkFlippedIO getLine
getPerson :: IO Person
getPerson = runFlippedIO $
Person
<$> (putStrLnFlipped "Enter your first name:" *> getLineFlipped)
<*> (putStrLnFlipped "Enter your last name:" *> getLineFlipped)
It runs things "backwards": ghci> getPerson
One
Enter your last name:
Two
Enter your first name:
Person "Two" "One"Are household appliances trying to replace humans?
But I think we're established the answer to the question I originally asked. Thanks for participating.
And what exactly is Israel doing there, on that land the size of an athletics track? Something very nefarious?
> Those who know their history also know that the current American administration is of a kind that usually ascends following the rules, but then never voluntarily leaves power.
and not really becoming of a top level Hacker News post. I requested a clarification from bojan and they did not respond to the request. We're all welcome to make our own interpretation of that.
If it's a strong claim it's not much of a gamble, is it? Talk is cheap.