I've just been investigating FRP in Haskell (mainly reactive-banana (testimonials!)), and I'm wondering is it common for them, and in case of reactive-banana what's the reason to operate in IO monad instead of being constrained to MonadIO, or rven better, any Monad (so that I could provide own stack)?
It seems to me that's because of focus on GUI programming, where you integrate it with some existing libraries that operate in IO? Would it be feasible to change it so that I could integrate it with custom monad stack?
If you are asking why
reactimate :: Frameworks t => Event t (IO ()) -> Moment t ()
expects an event with values of type IO () instead of allowing for a custom monad M () with instance MonadIO M, then the answer is this:
In practice, custom monad stacks only add state/reader/writer effects to the base IO monad. However, in theory, it is entirely possible to add fancy control mechanism like coroutines or non-determinism. I don't know how to integrate the internal state arising from combinators accumE with these more general effects, and I have no idea what it means for an event to happen in a non-deterministic context. That's why reactimate is restricted to IO.
If you have a custom monad stack that is of the state/reader/writer family, then it is usually possible to map it to a pure IO computation and use this with reactimate. If you find that this doesn't work out (I do think that there might be a problem), I would need a more detailed description of the concrete situation to be able to help.
Related
Every other monad comes with a transformer version, and from what I know the idea of a transformer is a generic extension of monads. Following how the other transformers are build, IOT would be something like
newtype IOT m a = IOT { runIOT :: m (IO a) }
for which I could make up useful applications on the spot: IOT Maybe can either do an IO action or nothing, IOT [] can build a list that can later be sequenced.
So why is there no IO transformer in Haskell?
(Notes: I've seen this post on Haskell Cafe, but can't make much sense of it. Also, the Hackage page for the ST transformer mentions a possibly related issue in its description, but doesn't offer any details.)
Consider the specific example of IOT Maybe. How would you write a Monad instance for that? You could start with something like this:
instance Monad (IOT Maybe) where
return x = IOT (Just (return x))
IOT Nothing >>= _ = IOT Nothing
IOT (Just m) >>= k = IOT $ error "what now?"
where m' = liftM (runIOT . k) m
Now you have m' :: IO (Maybe (IO b)), but you need something of type Maybe (IO b), where--most importantly--the choice between Just and Nothing should be determined by m'. How would that be implemented?
The answer, of course, is that it wouldn't, because it can't. Nor can you justify an unsafePerformIO in there, hidden behind a pure interface, because fundamentally you're asking for a pure value--the choice of Maybe constructor--to depend on the result of something in IO. Nnnnnope, not gonna happen.
The situation is even worse in the general case, because an arbitrary (universally quantified) Monad is even more impossible to unwrap than IO is.
Incidentally, the ST transformer you mention is implemented differently from your suggested IOT. It uses the internal implementation of ST as a State-like monad using magic pixie dust special primitives provided by the compiler, and defines a StateT-like transformer based on that. IO is implemented internally as an even more magical ST, and so a hypothetical IOT could be defined in a similar way.
Not that this really changes anything, other than possibly giving you better control over the relative ordering of impure side effects caused by IOT.
I'm currently building a new API, and one of the functions it currently provides is:
inSpan :: Tracer -> Text -> IO a -> IO a
I'm looking to move that Tracer into a monad, giving me a signature more like
inSpan :: MonadTracer m => Text -> m a -> m a
The implementation of inSpan uses bracket, which means I have two main options:
class MonadUnliftIO m => MonadTracer m
or
class MonadMask m => MonadTracer m
But which should I prefer? Note that I'm in control of all the types I've mentioned, which makes me slightly lean towards MonadMask as it doesn't enforce IO at the bottom (that is, we could perhaps have a pure MonadTracer instance).
Is there anything else I should consider?
Let's lay out the options first (repeating some of your question in the process):
MonadMask from the exceptions library. This can work on a wide range of monads and transformers, and does not require that the base monad be IO.
MonadUnliftIO from the unliftio-core (or unliftio) library. This library only works for monads with IO at their base, and which is somehow isomorphic to ReaderT env IO.
MonadBaseControl from the monad-control library. This library will require IO at the base, but will allow non-ReaderT.
Now the tradeoffs. MonadUnliftIO is the newest addition to the fray, and has the least developed library support. This means that, in addition to the limitations of what monads can be instances, many good instances just haven't been written yet.
The important question is: why does MonadUnliftIO make this seemingly arbitrary requirement around ReaderT-like things? This is to prevent issues with lost monadic state. For example, the semantics of bracket_ (put 1) (put 2) (put 3) are not really clear, and therefore MonadUnliftIO disallows a StateT instance.
MonadBaseControl relaxes the ReaderT restriction and has wider library support. It's also considered more complicated internally than the other two, but for your usages that shouldn't really matter. And it allows you to make mistakes with the monadic state as mentioned above. If you're careful in your usage, this won't matter.
MonadMask allows totally pure transformer stacks. I think there's a good argument to be had around the usefulness of modeling asynchronous exceptions in a pure stack, but I understand this kind of approach is something people want to do sometimes. In exchange for getting more instances, you still have the limitations around monadic state, plus the inability to lift some IO control actions, like timeout or forkIO.
My recommendation:
If you want to match the way most people are doing things today, it's probably best to choose MonadMask, it's the most well adopted solution.
If you want that goal, but you also need to do a timeout or withMVar or something, use MonadBaseControl.
And if you know there's a specific set of monads you need compatibility with, and want compile time guarantees about the correctness of your code vis-a-vis monadic state, use MonadUnliftIO.
So I have this sort of code all over my first serious haskell project:
f :: (MonadTrans t) => ExceptT () (t (StateT A B)) C
f = do mapExceptT lift $ do
lift $ do
...
lift $ do
...
r <- ...
...
return r
>>= \r -> ...
There definitely may be something wrong about how I try to achieve my goals (there might be simpler ways how to do it) but currently I am interested in learning how to handle a stack of monad transformers in some nicer way, if there is one. This is the only way I figured out how to get r in the context of B and lift it to a monad higher in the stack. Lifting whole blocks instead of initial statements is as far as I could get on my own.
What I also often end up with are chains of lift which I found out can be avoided with liftIO if the deep monad is IO. I am not aware of a generic way for other monads though.
Is there a pattern that one can follow when he ends up dealing with such stacks, and having to extract one value at some level, a different value at a different level, combine these and affect any of the two levels or maybe yet another one?
Can the stack be manipulated somehow without neither lifting whole blocks (which causes let and bound variables to be scoped and restricted to the inner block) nor having to lift . lift . ... lift individual actions?
This is a well-known problem with monad transformers in general. Researchers have devised various ways of handling it, none of which is clearly "best". Some of the known solutions include:
The mtl approach, which automatically lifts type classes of monads over its built-in monad transformers (and only its built-in monad transformers). This allows you to just write f :: (MonadState A m, MonadError () m) => m C if those are the only features of the monad that your function is using. Due to its extreme non-portability and a few other reasons, mtl is generally considered pseudo-deprecated. See this page and this question for the gory details.
If you have a particular monad stack you are using over and over again, you can wrap it in a newtype and write instances of the various monad type classes it supports manually. For Functor, Applicative, Monad, and any other type classes implemented by the top-level transformer in your stack, you can use GeneralizedNewtypeDeriving to have the compiler write the instances for you automatically; for other type classes, you will have to insert the appropriate number of lift calls for each method. The advantage of this approach is that it's more general and simpler to understand while giving you the same flexibility at the call site as mtl. The big problem with this approach is that it encourages using a single "mega-monad" for all operations rather than specifying only the needed operations, since adding any new monad transformer to the stack requires writing a whole new list of instances.
In most cases, you don't really want a monad that has "some arbitrary state of type A" and "some arbitrary exception-throwing capability". Rather, the different features offered by your monad stack have some semantic meaning in your mental model of your program. A variation of the previous approach is to create custom type classes for the effects beyond the basic Functor, Applicative, and Monad and write instances for the custom type classes on your newtype'd monad instead. This has a major advantage over the other approaches listed here: you can have a stack with multiple copies of the same monad transformer in it at different positions. This is the strategy I've used the most in my own programs so far.
A completely different approach is effect systems. Normally, an effect system has to be built in to a language's type system, but it's possible to encode an effect system in Haskell's type system. See the effect-monads package.
The usual approach is to use the mtl library rather than using transformers directly. I'm not sure what the story behind your t is, but the usual mtl approach is to use very general type signatures at definition sites, like
foo :: (MonadError e m, MonadState s m) => m Int
Then fix the actual transformer stacks at the call sites. A common recommendation is to wrap up the stack in a newtype to avoid muddying things up where they're used.
If this isn't your style (and it's not for everyone), you can still use the mtl methods to perform operations, while giving an explicit transformer stack. This should cut down on the manual lifting substantially. The advantage of this approach is that it gives you a better view of the interactions of effects at the definition sites; the disadvantage is that more code needs all the information.
I've had a look at the algo.monads and fluokitten documentation. I've also read through monad blog entries by Jim Duey, Konrad Hinsen and Leonardo Borges.
The closest I can find is Konrad Hinsen's library Monadic IO streams - but this doesn't appear to 'implement the monad interface' (for want of a better phrasing)
This is example using ST in Haskell
oneST :: ST s Int -- note that this works correctly for any s
oneST = do var <- newSTRef 0
modifySTRef var (+1)
readSTRef var
one :: Int
one = runST oneST
My question is: Is it possible to do the IO Monad from Haskell in Clojure? Could you provide an example?
There are a few ways to answer this question.
Yes
Trivially:
Think of IO as a monad transformer that grants the special permission of working with side effects. Then any monad in Clojure is an IO monad, as performing side effects is not a privileged operation in Clojure.
Fatuously: Clojure is Turing-complete, so you could implement all of Haskell, including the IO monad in Clojure. Haskell is Turing-complete, so you could implement all of Clojure in Haskell and expose the IO monad.
No
Philosophically: The essence of the IO monad, preserving purity while integrating with the type system, is incompatible with Clojure's impurity and dynamic typing. Any attempt to shoehorn in the IO monad would either be at odds with Clojure's philosophy or fail to capture the essential point of having an IO monad.
Maybe
Partially: The monadic-io-streams library linked to in the question is intended for use with the algo.monads library, or its predecessor. The monadic interface is the state monad. Monadic-io-streams provides some jailed IO monadic functions to work with it. This does not prevent you from using any other functions with side effects, and without a type system integrating IO there is no systematic way to say which is which. This is not the IO monad; it just does a few things similar to the IO monad. This is interesting but of dubious utility.
Someday: There is interest in Typed Clojure. If side effects are added to the type system, then it may become desirable to isolate them in a structured manner for some purposes and give reason for the existence of something like an IO monad in Typed Clojure.
I'm thinking about ways to use Haskell's type system to enforce modularity in a program. For example, if I have a web application, I'm curious if there's a way to separate all database code from CGI code from filesystem code from pure code.
For example, I'm envisioning a DB monad, so I could write functions like:
countOfUsers :: DB Int
countOfUsers = select "count(*) from users"
I would like it to be impossible to use side effects other than those supported by the DB monad. I am picturing a higher-level monad that would be limited to direct URL handlers and would be able to compose calls to the DB monad and the IO monad.
Is this possible? Is this wise?
Update: I ended up achieving this with Scala instead of Haskell: http://moreindirection.blogspot.com/2011/08/implicit-environment-pattern.html
I am picturing a higher-level monad that would be limited to direct URL handlers and would be able to compose calls to the DB monad and the IO monad.
You can certainly achieve this, and get very strong static guarantees about the separation of the components.
At its simplest, you want a restricted IO monad. Using something like a "tainting" technique, you can create a set of IO operations lifted into a simple wrapper, then use the module system to hide the underlying constructors for the types.
In this way you'll only be able to run CGI code in a CGI context, and DB code in a DB context. There are many examples on Hackage.
Another way is to construct an interpreter for the actions, and then use data constructors to describe each primitive operation you wish. The operations should still form a monad, and you can use do-notation, but you'll instead be building a data structure that describes the actions to run, which you then execute in a controlled way via an interpreter.
This gives you perhaps more introspection than you need in typical cases, but the approach does give you full power to insspect user code before you execute it.
I think there's a third way beyond the two Don Stewart mentioned, which may even be simpler:
class Monad m => MonadDB m where
someDBop1 :: String -> m ()
someDBop2 :: String -> m [String]
class Monad m => MonadCGI m where
someCGIop1 :: ...
someCGIop2 :: ...
functionWithOnlyDBEffects :: MonadDB m => Foo -> Bar -> m ()
functionWithOnlyDBEffects = ...
functionWithDBandCGIEffects :: (MonadDB m, MonadCGI m) => Baz -> Quux -> m ()
functionWithDBandCGIEffects = ...
instance MonadDB IO where
someDBop1 = ...
someDBop2 = ...
instance MonadCGI IO where
someCGIop1 = ...
someCGIop2 = ...
The idea is very simply that you define type classes for the various subsets of operations you want to separate out, and then parametrize your functions using them. Even if the only concrete monad you ever make an instance of the classes is IO, the functions parametrized on any MonadDB will still only be allowed to use MonadDB operations (and ones built from them), so you achieve the desired result. And in a "can do anything" function in the IO monad, you can use MonadDB and MonadCGI operations seamlessly, because IO is an instance.
(Of course, you can define other instances if you want to. Ones to lift the operations through various monad transformers would be straightforward, and I think there's actually nothing stopping you from writing instances for the "wrapper" and "interpreter" monads Don Stewart mentions, thereby combining the approaches - although I'm not sure if there's a reason you would want to.)
Thanks for this question!
I did some work on a client/server web framework that used monads to distinguish between different exection environments. The obvious ones were client-side and server-side, but it also allowed you to write both-side code (which could run on both client and server, because it didn't contain any special features) and also asynchronous client-side which was used for writing non-blocking code on the client (essentially a continuation monad on the client-side). This sounds quite related to your idea of distinguishing between CGI code and DB code.
Here are some resources about my project:
Slides from a presentation that I did about the project
Draft paper that I wrote with Don Syme
And I also wrote my Bachelor thesis on this subject (which is quite long though)
I think this is an interesting approach and it can give you interesting guarantees about the code. There are some tricky questions though. If you have a server-side function that takes an int and returns int, then what should be the type of this function? In my project, I used int -> int server (but it may be also possible to use server (int -> int).
If you have a couple of functions like this, then it isn't as straightforward to compose them. Instead of writing goo (foo (bar 1)), you need to write the following code:
do b <- bar 1
f <- foo b
return goo f
You could write the same thing using some combinators, but my point is that composition is a bit less elegant.