How to use literal haskell functions in DSL? - haskell

I'd like to use literal haskell functions in a dsl as follows:
program :: forall m . DSL m => m ()
program = do
stm $ Stm (Var "a")
-- this way:
f <- fun $ \(a :: Expr a) (b :: Expr b) -> do
-- function body is of the same monad `m` as the one in top level
stm $ Stm (Var "b")
stm $ Stm $ Apply f (Var "c")
pure ()
.. and turn the above into code ([Stm]).
To make the functions work there is a helper class Fun (code below)
that saturates the function with fresh variables until it reaches
function body,
then returns both the list of arguments and body itself so that they
could be made into function syntax[1]. There is a recursive case to
generate arguments[2] and a base case to evaluate body to [Stm].[3]
The worrisome instance is the base case[4], which currently requires
{-# INCOHERENT #-}, because ghc can't choose a Fun instance because
function's body in the program is ambiguous (while it should just be
whatever m is at top level code).
So the question is:
is there a way to force the body to always use the
same m as in top level and not require incoherent instances?
A stub AST, the MTL-style DSL "effect" and a sample instance of the class:
-- | An AST
data Expr a
= Var String
| Apply String (Expr a)
| Function String [String] [Stm]
data Stm = Stm (Expr ())
-- | The "effect"
class Monad m => DSL m where
freshName :: m String -- generate fresh variable name
stm :: Stm -> m () -- emit statement
toAST :: m a -> m [Stm] -- turn code `m a` into [Stm] (without emitting it)
fun :: Fun f m => f -> m String -- emit function f, return its name
-- | Helper class to convert literal haskell functions to the dsl
class Fun f m where
mkFun :: DSL m => f -> [String] -> m ([String], [Stm])
instance Fun f m => Fun (Expr a -> f) m where
mkFun f acc = do
name <- freshName -- [2]
mkFun (f $ Var name) (name : acc)
instance {-# INCOHERENT #-} (m0 ~ m) => Fun (m0 a) m where -- [4]
mkFun m args = do
fname <- freshName
body <- toAST m -- [3]
return (args, body)
-- | A sample implementation
instance DSL (StateT Int (Writer [Stm])) where
freshName = do
n <- get
put $ n + 1
return $ "var" <> show n
stm stm' = tell [stm']
toAST m = do
state0 <- get
let ((_, state1), w) = run m state0
put state1
return w
fun f = do
(args, body) <- mkFun f []
name <- freshName
stm $ Stm $ Function name args body -- [1]
return name
run :: StateT Int (Writer [Stm]) a -> Int -> ((a, Int), [Stm])
run m s = runWriter $ runStateT m s

I guess one way is to mark the base case of the recursion yourself.
newtype Cook m a = Cook (m a)
deriving instance DSL m => DSL (Cook m)
instance Fun f m => Fun (Expr a -> f) m
instance m0 ~ m => Fun (Cook m0 a) (Cook m)
type SampleImplRaw = StateT Int (Writer [Stm])
type SampleImpl = Cook SampleImplRaw
instance DSL SampleImpl
I haven't typed this into the compiler, so I'm not sure, but it may be that you get into a funny situation where you want a DSL m instance, and have a DSL (Cook m) instance in scope, but the compiler can't figure out how to get from A to B. In such a case it should be possible to coerce the offending term to use the Cook m instance.
Another way might be to try making the base case have a different kind. Something like this:
instance Fun f m => Fun (Expr a -> f) m
instance (m ~ m', p ~ p', p ~ '()) => Fun (m p a) (m' p')
data SampleImplRaw (x :: ()) a = {- whatever you would have written before for new data declarations -}
type SampleImpl = SampleImplRaw '()
newtype Const1 (x :: ()) m a = Const1 (m a) deriving (EVERYTHING) -- still need a cook for mere monad transformer stacks
I guess probably if your plan is mostly to use transformer stacks, the first one will be less roundabout; if your plan is mostly to define new data types, the second will have a cleaner user experience.

Related

Why is FunctionalDependency needed for defining MonadReader?

I just managed to understand the definition of the class MonadReader
class Monad m => MonadReader r m | m -> r where
...
After reading the document of Functional Dependency in Haskell, now I can understand that | m -> r specifies that type variable r is uniquely decided by m. I think this requirement is reasonable based on the few typical instances of MonadReader I have seen so far (e.g. Reader), but it seems to me that we can still define instances like Reader even without this functional dependency clause.
My question is why we need functional dependency in the definition of MonadReader? Is this functionally necessary for defining MonadReader in a sense that MonadReader cannot be properly defined without it, or it is merely a restriction to limit the ways how MonadReader can be used so that the instances of MonadReader will all behave in a certain expected way?
It is needed to make type inference work in a way which is more convenient to the user.
For example, without the fundep this would not compile:
action :: ReaderT Int IO ()
action = do
x <- ask
liftIO $ print x
To make the above compile we would need to write
action :: ReadertT Int IO ()
action = do
x <- ask :: ReadertT Int IO Int
liftIO $ print x
This is because, without the fundep, the compiler can not infer that x is an Int. After all a monad ReadertT Int IO might have multiple instances
instance MonadReader Int (ReaderT Int IO) where
ask = ReaderT (\i -> return i)
instance MonadReader Bool (ReaderT Int IO) where
ask = ReaderT (\i -> return (i != 0))
instance MonadReader String (ReaderT Int IO) where
ask = ReaderT (\i -> return (show i))
-- etc.
so the programmer must provide some annotation which forces x :: Int, or the code is ambiguous.
This is not really an answer, but it's much too long for a comment. You are correct that it's possible to define the MonadReader class without a fundep. In particular, the type signature of each method determines every class parameter. It would be quite possible to define a finer hierarchy.
class MonadReaderA r m where
askA :: m r
askA = readerA id
readerA :: (r -> a) -> m a
readerA f = f <$> askA
-- This effect is somewhat different in
-- character and requires special lifting.
class MonadReaderA r m => MonadReaderB r m where
localB :: (r -> r) -> m a -> m a
class MonadReaderB r m
=> MonadReader r m | m -> r
ask :: MonadReader r m => m r
ask = askA
reader
:: MonadReader r m
=> (r -> a) -> m a
reader = readerA
local
:: MonadReader r m
=> (r -> r) -> m a -> m a
local = localB
The main problem with this approach is that users have to write a bunch of instances.
I think the source of confusion is that in the definition of
class Monad m => MonadReader r m | m -> r where
{- ... -}
It is implicitly asumed that m contains r itself (for common instances). Let me use a lighter definiton of Reader as
newtype Reader r a = Reader {runReader :: r -> a}
When the r parameter is chosen you can easely define a monad instance for Reader r. That means that in the type class definition m should be substitute for Reader r. So take a look at how the expresion ends up being:
instance MonadReader r (Reader r) where -- hey!! r is duplicated now
{- ... -} -- The functional dependecy becomes Reader r -> r which makes sense
But why do we need this?. Look at the definition of ask within the MonadReader class.
class Monad m => MonadReader r m | m -> r where
ask :: m r -- r and m are polymorphic here
{- ... -}
Without the fun-dep nothing could stop me for defining ask in a way to return a different type as the state. Even more, I could define many instances of monad reader for my type. As an example, this would be valid definitions without func-dep
instance MonadReader Bool (Reader r) where
-- ^^^^ ^
-- | |- This is state type in the user defined newtype
-- |- this is the state type in the type class definition
ask :: Reader r Bool
ask = Reader (\_ -> True) -- the function that returns True constantly
{- ... -}
instance MonadReader String (Reader r) where
-- ^^^^^^ ^
-- | |- This is read-state type in the user defined newtype
-- |- this is the read-state type in the type class definition
ask :: Reader r String
ask = Reader (\_ -> "ThisIsBroken") -- the function that returns "ThisIsBroken" constantly
{- ... -}
So if I had a value val :: ReaderT Int IO Double what would be the result of ask. We'd need to specify a type signature as below
val :: Reader Int Double
val = do
r <- ask :: Reader Int String
liftIO $ putStrLn r -- Just imagine you can use liftIO
return 1.0
> val `runReader` 1
"ThisIsBroken"
1.0
val :: Reader Int Double
val = do
r <- ask :: Reader Int Bool
liftIO $ print r -- Just imagine you can use liftIO
return 1.0
> val `runReader` 1
True
1.0
Aside from being senseless, it is unconvinient to be specifiying the type over and over.
As a conclusion using the actual definition of ReaderT. When you have something like val :: ReaderT String IO Int the functional dependency says Such a type might have only one single instance of MonadReader typeclass which is defined to be the one that uses String as r

Can the type of this function be declared in standard Haskell

The following program compiles under GHC 8.0.2 with no language extensions, and produces the expected two lines of output.
However, it does not compile if the (non-top-level) type declaration for the value write' is removed.
Also, I cannot find any (top-level) type declaration for the function write.
I find this rather odd. If this is acceptable standard Haskell, surely it should be possible to create a type declaration for the function write.
So my question is: is there such a type declaration?
import Control.Monad.Trans.Maybe (MaybeT, runMaybeT)
import Control.Monad.Writer (MonadTrans, Writer, lift, runWriter, tell, when)
import ListT (ListT, toList) -- Volkov's list-t package
logging = True
write x = when logging write' where
write' :: MonadTrans m => m (Writer [String]) ()
write' = lift $ tell [x]
f :: ListT (Writer [String]) String
f = do
write "Hello from f"
return "ABC"
g :: MaybeT (Writer [String]) Int
g = do
write "Hello from g"
return 123
main :: IO ()
main = do
print $ runWriter $ toList f
print $ runWriter $ runMaybeT g
Using GHCi (remember to put this into a separate file and load it on GHCi's command line lest you get confused by GHCi's altered typing rules):
> :t write
write :: (Applicative (m (Writer [String])), MonadTrans m) =>
String -> m (Writer [String]) ()
Why? Well,
write' :: MonadTrans m => m (Writer [String]) ()
when :: Applicative f => Bool -> f () -> f ()
when logging :: Applicative f => f () -> f ()
so, when logging write' must unify write''s m (Writer [String]) with when loggings's f, causing the combined constraint (Applicative (m (Writer [String])), MonadTrans m). But wait, let's remove the type signatures and see what the most general type is:
-- equivalent but slightly easier to talk about
write = when logging . lift . tell . (:[])
(:[]) :: a -> [a]
tell :: MonadWriter w m -> w -> m ()
lift :: (Monad m, MonadTrans t) => m a -> t m a
tell . (:[]) :: MonadWriter [a] m => a -> m ()
lift . tell . (:[]) :: (MonadWriter [a] m, MonadTrans t) => a -> t m ()
when logging . lift . tell . (:[]) = write
:: (Applicative (t m), MonadWriter [a] m, MonadTrans t) => a -> t m ()
-- GHCi agrees
Per se, there's nothing wrong with this type. However, standard Haskell does not allow this. In standard Haskell, a constraint must be of the form C v or C (v t1 t2 ...) where v is a type variable. In the compiling case, this holds: the Applicative constraint has the type variable m on the outside, and the MonadTrans is just m. This is true in the non-compiling version, too, but we also have the constraint MonadWriter ([] a) m. [] is no type variable, so the type here is rejected. This constraint arises in the compiling version, too, but the type signatures nail the variables down to produce MonadWriter [String] (Writer [String]), which is immediately satisfied and does not need to appear in the context of write.
The restriction is lifted by enabling FlexibleContexts (preferably via a {-# LANGUAGE FlexibleContexts #-} pragma, but also maybe by -XFlexibleContexts). It originally existed to prevent things such as the following:
class C a where c :: a -> a
-- no instance C Int
foo :: C Int => Int
foo = c (5 :: Int)
-- with NoFlexibleContexts: foo's definition is in error
-- with FlexibleContexts: foo is fine; all usages of foo are in error for
-- not providing C Int. This might obscure the source of the problem.
-- slightly more insiduous
data Odd a = Odd a
-- no Eq (Odd a)
oddly (Odd 0) (Odd 0) = False
oddly l r = l == r
-- oddly :: (Num a, Eq (Odd a), Eq a) => Odd a -> Odd a -> Bool
-- Now the weird type is inferred! With FlexibleContexts,
-- the weird constraint can propagate quite far, causing errors in distant
-- places. This is confusing. NoFlexibleContexts places oddly in the spotlight.
But it happens to get in the way a lot when you have MultiParamTypeClasses on.

Taking monadic functions out of a monad

Haskell has the function join, which "runs" a monadic action which is inside a monad:
join :: Monad m => m (m a) -> m a
join m = m >>= \f -> f
We can write a similar function for monadic functions with one argument:
join1 :: Monad m => m (a -> m b) -> (a -> m b)
join1 m arg1 = m >>= \f -> f arg1
And for two arguments:
join2 :: Monad m => m (a -> b -> m c) -> (a -> b -> m c)
join2 m arg1 arg2 = m >>= \f -> f arg1 arg2
Is it possible to write a general function joinN, that can handle monadic functions with N arguments?
You can do something like this with a fair amount of ugliness if you really desire.
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
import Control.Monad (join, liftM)
class Joinable m z | z -> m where
joins :: m z -> z
instance Monad m => Joinable m (m a) where
joins = join
instance (Monad m, Joinable m z) => Joinable m (r -> z) where
joins m r = joins (liftM ($ r) m)
But, as you can see this relies on some shaky typeclass magic (in particular, the unenviable UndecidableInstances). It is quite possibly better—if ugly looking—to write all of the instances join1...join10 and export them directly. This is the pattern established in the base library as well.
Notably, inference won't work too well under this regime. For instance
λ> joins (return (\a b -> return (a + b))) 1 2
Overlapping instances for Joinable ((->) t0) (t0 -> t0 -> IO t0)
arising from a use of ‘joins’
Matching instances:
instance Monad m => Joinable m (m a)
-- Defined at /Users/tel/tmp/ASD.hs:11:10
instance (Monad m, Joinable m z) => Joinable m (r -> z)
-- Defined at /Users/tel/tmp/ASD.hs:14:10
but if we give an explicit type to our argument
λ> let {q :: IO (Int -> Int -> IO Int); q = return (\a b -> return (a + b))}
then it can still work as we hope
λ> joins q 1 2
3
This arises because with typeclasses alone it becomes quite difficult to indicate whether you want to operate on the monad m in the final return type of the function chain or the monad (->) r that is the function chain itself.
The short answer is no. The slightly longer answer is you could probably define an infix operator.
Take a look at the implementation for liftM: http://hackage.haskell.org/package/base-4.7.0.2/docs/src/Control-Monad.html#liftM
It defines up to liftM5. This is because it's not possible to define liftMN, just like your joinN isn't possible.
But we can take a lesson from Appicative <$> and <*> and define our own infix operator:
> let infixr 1 <~> ; x <~> f = fmap ($ x) f
> :t (<~>)
(<~>) :: Functor f => a -> f (a -> b) -> f b
> let foo x y = Just (x + y)
> let foobar = Just foo
> join $ 1 <~> 2 <~> foobar
Just 3
This is quite reminiscent of a common applicative pattern:
f <$> a1 <*> a2 .. <*> an
join $ a1 <~> a2 .. <~> an <~> f
A single function for every possible N? Not really. Generalizing over functions with different numbers of arguments like this is difficult in Haskell, in part because "number of arguments" is not always well-defined. The following are all valid specializations of id's type:
id :: a -> a
id :: (a -> a) -> a -> a
id :: (a -> a -> a) -> a -> a -> a
...
We'd need some way to get N at the type level, and then do a different thing depending on what N is.
Existing "variadic" functions like printf do this with typeclasses. They establish what N is by induction on ->: they have a "base case" instance for a non-function type like String and a recursive instance for functions:
instance PrintfType String ...
instance (PrintfArg a, PrintfType r) => PrintfType (a -> r) ...
We can (after a lot of thinking :P) use the same approach here, with one caveat: our base case is a bit ugly. We want to start with the normal join, which produces a result of type m a; the problem is that to support any m a, we have to overlap with normal functions. This means that we need to enable a few scary extensions and that we might confuse the type inference system when we actually use our joinN. But, with the right type signatures in place, I believe it should work correctly.
First off, here's the helper class:
class Monad m => JoinN m ma where
joinN :: m ma -> ma
ma will take the relevant function type like a -> m b, a -> b -> m c and so on. I couldn't figure out how to leave m out of the class definition, so right off the bat we need to enable MultiParamTypeClasses.
Next, our base case, which is just normal join:
instance Monad m => JoinN m (m a) where
joinN = join
Finally, we have our recursive case. What we need to do is "peel off" an argument and then implement the function in terms of a smaller joinN. We do this with ap, which is <*> specialized to monads:
instance (Monad m, JoinN m ma) => JoinN m (b -> ma) where
joinN m arg = joinN (m `ap` return arg)
We can read the => in the instance as implication: if we know how to joinN an ma, we also know how to do a b -> ma.
This instance is slightly weird, so it requires FlexibleInstances to work. More troublingly, because our base case (m (m a)) is made up entirely of variables, it actually overlaps with a bunch of other reasonable types. To actually make this work we have to enable OverlappingInstances and IncoherentInstances, which are relatively tricky and bug-prone.
After a bit of cursory testing, it seems to work:
λ> let foo' = do getLine >>= \ x -> return $ \ a b c d -> putStrLn $ a ++ x ++ b ++ x ++ c ++ x ++ d
λ> let join4 m a b c d = m >>= \ f -> f a b c d
λ> join4 foo' "a" "b" "c" "d"
a b c d
λ> joinN foo' "a" "b" "c" "d"
a b c d

Can I make a Lens with a Monad constraint?

Context: This question is specifically in reference to Control.Lens (version 3.9.1 at the time of this writing)
I've been using the lens library and it is very nice to be able to read and write to a piece (or pieces for traversals) of a structure. I then had a though about whether a lens could be used against an external database. Of course, I would then need to execute in the IO Monad. So to generalize:
Question:
Given a getter, (s -> m a) and an setter (b -> s -> m t) where m is a Monad, is possible to construct Lens s t a b where the Functor of the lens is now contained to also be a Monad? Would it still be possible to compose these with (.) with other "purely functional" lenses?
Example:
Could I make Lens (MVar a) (MVar b) a b using readMVar and withMVar?
Alternative:
Is there an equivalent to Control.Lens for containers in the IO monad such as MVar or IORef (or STDIN)?
I've been thinking about this idea for some time, which I'd call mutable lenses. So far, I haven't made it into a package, let me know, if you'd benefit from it.
First let's recall the generalized van Laarhoven Lenses (after some imports we'll need later):
{-# LANGUAGE RankNTypes #-}
import qualified Data.ByteString as BS
import Data.Functor.Constant
import Data.Functor.Identity
import Data.Traversable (Traversable)
import qualified Data.Traversable as T
import Control.Monad
import Control.Monad.STM
import Control.Concurrent.STM.TVar
type Lens s t a b = forall f . (Functor f) => (a -> f b) -> (s -> f t)
type Lens' s a = Lens s s a a
we can create such a lens from a "getter" and a "setter" as
mkLens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
mkLens g s f x = fmap (s x) (f (g x))
and get a "getter"/"setter" from a lens back as
get :: Lens s t a b -> (s -> a)
get l = getConstant . l Constant
set :: Lens s t a b -> (s -> b -> t)
set l x v = runIdentity $ l (const $ Identity v) x
as an example, the following lens accesses the first element of a pair:
_1 :: Lens' (a, b) a
_1 = mkLens fst (\(x, y) x' -> (x', y))
-- or directly: _1 f (a,c) = (\b -> (b,c)) `fmap` f a
Now how a mutable lens should work? Getting some container's content involves a monadic action. And setting a value doesn't change the container, it remains the same, just as a mutable piece of memory does. So the result of a mutable lens will have to be monadic, and instead of the return type container t we'll have just (). Moreover, the Functor constraint isn't enough, since we need to interleave it with monadic computations. Therefore, we'll need Traversable:
type MutableLensM m s a b
= forall f . (Traversable f) => (a -> f b) -> (s -> m (f ()))
type MutableLensM' m s a
= MutableLensM m s a a
(Traversable is to monadic computations what Functor is to pure computations).
Again, we create helper functions
mkLensM :: (Monad m) => (s -> m a) -> (s -> b -> m ())
-> MutableLensM m s a b
mkLensM g s f x = g x >>= T.mapM (s x) . f
mget :: (Monad m) => MutableLensM m s a b -> s -> m a
mget l s = liftM getConstant $ l Constant s
mset :: (Monad m) => MutableLensM m s a b -> s -> b -> m ()
mset l s v = liftM runIdentity $ l (const $ Identity v) s
As an example, let's create a mutable lens from a TVar within STM:
alterTVar :: MutableLensM' STM (TVar a) a
alterTVar = mkLensM readTVar writeTVar
These lenses are one-sidedly directly composable with Lens, for example
alterTVar . _1 :: MutableLensM' STM (TVar (a, b)) a
Notes:
Mutable lenses could be made more powerful if we allow that the modifying function to include effects:
type MutableLensM2 m s a b
= (Traversable f) => (a -> m (f b)) -> (s -> m (f ()))
type MutableLensM2' m s a
= MutableLensM2 m s a a
mkLensM2 :: (Monad m) => (s -> m a) -> (s -> b -> m ())
-> MutableLensM2 m s a b
mkLensM2 g s f x = g x >>= f >>= T.mapM (s x)
However, it has two major drawbacks:
It isn't composable with pure Lens.
Since the inner action is arbitrary, it allows you to shoot yourself in the foot by mutating this (or other) lens during the mutating operation itself.
There are other possibilities for monadic lenses. For example, we can create a monadic copy-on-write lens that preserves the original container (just as Lens does), but where the operation involves some monadic action:
type LensCOW m s t a b
= forall f . (Traversable f) => (a -> f b) -> (s -> m (f t))
I've made jLens - a Java library for mutable lenses, but the API is of course far from being as nice as Haskell lenses.
No, you can not constrain the "Functor of the lens" to also be a Monad. The type for a Lens requires that it be compatible with all Functors:
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
This reads in English something like: A Lens is a function, which, for all types f where f is a Functor, takes an (a -> f b) and returns an s -> f t. The key part of that is that it must provide such a function for every Functor f, not just some subset of them that happen to be Monads.
Edit:
You could make a Lens (MVar a) (MVar b) a b, since none of s t a, or b are constrained. What would the types on the getter and setter needed to construct it be then? The type of the getter would be (MVar a -> a), which I believe could only be implemented as \_ -> undefined, since there's nothing that extracts the value from an MVar except as IO a. The setter would be (MVar a -> b -> MVar b), which we also can't define since there's nothing that makes an MVar except as IO (MVar b).
This suggests that instead we could instead make the type Lens (MVar a) (IO (MVar b)) (IO a) b. This would be an interesting avenue to pursue further with some actual code and a compiler, which I don't have right now. To combine that with other "purely functional" lenses, we'd probably want some sort of lift to lift the lens into a monad, something like liftLM :: (Monad m) => Lens s t a b -> Lens s (m t) (m a) b.
Code that compiles (2nd edit):
In order to be able to use the Lens s t a b as a Getter s a we must have s ~ t and a ~ b. This limits our type of useful lenses lifted over some Monad to the widest type for s and t and the widest type for a and b. If we substitute b ~ a into out possible type we would have Lens (MVar a) (IO (MVar a)) (IO a) a, but we still need MVar a ~ IO (MVar a) and IO a ~ a. We take the wides of each of these types, and choose Lens (IO (MVar a)) (IO (MVar a)) (IO a) (IO a), which Control.Lens.Lens lets us write as Lens' (IO (MVar a)) (IO a). Following this line of reasoning, we can make a complete system for combining "purely functional" lenses with lenses on monadic values. The operation to lift a "purely function" lens, liftLensM, then has the type (Monad m) => Lens' s a -> LensF' m s a, where LensF' f s a ~ Lens' (f s) (f a).
{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}
module Main (
main
) where
import Control.Lens
import Control.Concurrent.MVar
main = do
-- Using MVar
putStrLn "Ordinary MVar"
var <- newMVar 1
output var
swapMVar var 2
output var
-- Using mvarLens
putStrLn ""
putStrLn "MVar accessed through a LensF' IO"
value <- (return var) ^. mvarLens
putStrLn $ show value
set mvarLens (return 3) (return var)
output var
-- Debugging lens
putStrLn ""
putStrLn "MVar accessed through a LensF' IO that also debugs"
value <- readM (debug mvarLens) var
putStrLn $ show value
setM (debug mvarLens) 4 var
output var
-- Debugging crazy box lens
putStrLn ""
putStrLn "MVar accessed through a LensF' IO that also debugs through a Box that's been lifted to LensF' IO that also debugs"
value <- readM ((debug mvarLens) . (debug (liftLensM boxLens))) var
putStrLn $ show value
setM ((debug mvarLens) . (debug (liftLensM boxLens))) (Box 5) var
output var
where
output = \v -> (readMVar v) >>= (putStrLn . show)
-- Types to write higher lenses easily
type LensF f s t a b = Lens (f s) (f t) (f a) (f b)
type LensF' f s a = Lens' (f s) (f a)
type GetterF f s a = Getter (f s) (f a)
type SetterF f s t a b = Setter (f s) (f t) (f a) (f b)
-- Lenses for MVars
setMVar :: IO (MVar a) -> IO a -> IO (MVar a)
setMVar ioVar ioValue = do
var <- ioVar
value <- ioValue
swapMVar var value
return var
getMVar :: IO (MVar a) -> IO a
getMVar ioVar = do
var <- ioVar
readMVar var
-- (flip (>>=)) readMVar
mvarLens :: LensF' IO (MVar a) a
mvarLens = lens getMVar setMVar
-- Lift a Lens' to a Lens' on monadic values
liftLensM :: (Monad m) => Lens' s a -> LensF' m s a
liftLensM pureLens = lens getM setM
where
getM mS = do
s <- mS
return (s^.pureLens)
setM mS mValue = do
s <- mS
value <- mValue
return (set pureLens value s)
-- Output when a Lens' is used in IO
debug :: (Show a) => LensF' IO s a -> LensF' IO s a
debug l = lens debugGet debugSet
where
debugGet ioS = do
value <- ioS^.l
putStrLn $ show $ "Getting " ++ (show value)
return value
debugSet ioS ioValue = do
value <- ioValue
putStrLn $ show $ "Setting " ++ (show value)
set l (return value) ioS
-- Easier way to use lenses in a monad (if you don't like writing return for each argument)
readM :: (Monad m) => GetterF m s a -> s -> m a
readM l s = (return s) ^. l
setM :: (Monad m) => SetterF m s t a b -> b -> s -> m t
setM l b s = set l (return b) (return s)
-- Another example lens
newtype Boxed a = Box {
unBox :: a
} deriving Show
boxLens :: Lens' a (Boxed a)
boxLens = lens Box (\_ -> unBox)
This code produces the following output:
Ordinary MVar
1
2
MVar accessed through a LensF' IO
2
3
MVar accessed through a LensF' IO that also debugs
"Getting 3"
3
"Setting 4"
4
MVar accessed through a LensF' IO that also debugs through a Box that's been lifted to LensF' IO that also debugs
"Getting 4"
"Getting Box {unBox = 4}"
Box {unBox = 4}
"Setting Box {unBox = 5}"
"Getting 4"
"Setting 5"
5
There's probably a better way to write liftLensM without resorting to using lens, (^.), set and do notation. Something seems wrong about building lenses by extracting the getter and setter and calling lens on a new getter and setter.
I wasn't able to figure out how to reuse a lens as both a getter and a setter. readM (debug mvarLens) and setM (debug mvarLens) both work just fine, but any construct like 'let debugMVarLens = debug mvarLens' loses either the fact it works as a Getter, the fact it works as a Setter, or the knowledge that Int is an instance of show so it can me used for debug. I'd love to see a better way of writing this part.
I had the same problem. I tried the methods in Petr and Cirdec's answers but never got to the point I wanted to. Started working on the problem, and at the end, I published the references library on hackage with a generalization of lenses.
I followed the idea of the yall library to parameterize the references with monad types. As a result there is an mvar reference in Control.Reference.Predefined. It is an IO reference, so an access to the referenced value is done in an IO action.
There are also other applications of this library, it is not restricted to IO. An additional feature is to add references (so adding _1 and _2 tuple accessors will give a both traversal, that accesses both fields). It can also be used to release resources after accessing them, so it can be used to manipulate files safely.
The usage is like this:
test =
do result <- newEmptyMVar
terminator <- newEmptyMVar
forkIO $ (result ^? mvar) >>= print >> (mvar .= ()) terminator >> return ()
hello <- newMVar (Just "World")
forkIO $ ((mvar & just & _tail & _tail) %~= ('_':) $ hello) >> return ()
forkIO $ ((mvar & just & element 1) .= 'u' $ hello) >> return ()
forkIO $ ((mvar & just) %~= ("Hello" ++) $ hello) >> return ()
x <- runMaybeT $ hello ^? (mvar & just)
mvar .= x $ result
terminator ^? mvar
The operator & combines lenses, ^? is generalized to handle references of any monad, not just a referenced value that may not exist. The %~= operator is an update of a monadic reference with a pure function.

Why does the following ReaderT String IO lose an IO action?

module Main (main) where
import Control.Monad.Reader
p1 :: String -> IO ()
p1 = putStrLn . ("Apple "++)
p2 :: String -> IO ()
p2 = putStrLn . ("Pear "++)
main :: IO ()
main = do
p1 "x"
p2 "y"
r "z"
r :: String -> IO ()
r = do
p1
p2
It prints:
Apple x
Pear y
Pear z
Why?
The problem is in r. Given the following definition of Reader monad:
instance Monad ((->) e) where
return = const
f >>= g = \x -> g (f x) x
We can simplify r:
r = p1 >> p2
= (>>=) p1 (\_ -> p2)
= (\f g x -> g (f x) x) p1 (\_ -> p2)
= \x -> (\_ -> p2) (p1 x) x
= \x -> p2 x
This also shows that Reader's (>>) is just const with a bit more specific type.
If you want to distribute the environment and then execute both actions, you have to bind the result of applying p1 to the environment, for example:
r = do a1 <- p1
a2 <- p2
return (a1 >> a2)
Or using Applicative:
r = (>>) <$> p1 <*> p2
Expanding on the Reader part, Control.Monad.Reader provides three variants of Reader.
the implicit (->) e, which is what the function r uses
the monad transformer ReaderT e m, a newtype wrapper for functions of type e -> m a
the explicit Reader e, defined in terms of ReaderT as ReaderT e Identity
Without any further information, the implicit (->) e will be used. Why?
The overall type of do block is given by the last expression, which is also constrained to be of the form Monad m => m a for some m and a.
Looking back at r, it's clear that the do block has a type String -> IO () as given by the type of r and also p2. It also requires String -> IO () to be Monad m => m a. Now, unifying these two types:
m = (->) String
a = IO ()
This matches (->) e monad instance by choosing e = String.
Being a monad transformer, ReaderT takes care of the inner plumbing to make sure the actions of the inner monad are properly sequenced and executed. To select ReaderT, it is necessary to explicitly mention it (usually in a type signature, but functions which fix the type to be ReaderT, such as runReaderT, also work):
r :: ReaderT String IO ()
r = do ? p1
? p2
r' :: String -> IO ()
r' = runReaderT r
This comes with another problem, p1 and p2 have a type String -> IO (), which doesn't match the required ReaderT String IO ().
The ad-hoc solution (tailored exactly for this situation), is just to apply
ReaderT :: (e -> m a) -> ReaderT e m a
To obtain something more general, MonadIO type class can lift IO actions into the transformer and MonadReader type class allows accessing the environment. These two type classes work as long as there is IO (or ReaderT respectively) somewhere in the transformer stack.
lift' :: (MonadIO m, MonadReader a m) => (a -> IO b) -> m b
lift' f = do
env <- ask -- get environment
let io = f env -- apply f to get the IO action
liftIO io -- lift IO action into transformer stack
Or more concisely:
lift' f = ask >>= liftIO . f
Regarding your question in comments, you can implement the relevant instances in this way:
newtype ReaderT e m a = ReaderT { runReaderT :: e -> m a }
instance Monad m => Monad (ReaderT e m) where
return = ReaderT . const . return
-- The transformers package defines it as "lift . return".
-- These two definitions are equivalent, though.
m >>= f = ReaderT $ \e -> do
a <- runReaderT m e
runReaderT (f a) e
instance Monad m => MonadReader e (ReaderT e m) where
ask = ReaderT return
local f m = ReaderT $ runReaderT m . f
reader f = ReaderT (return . f)
The actual typeclass can be found in the mtl package (package, type class), the newtype and Monad instance in transformers package (package, type class).
As for making a e -> m a Monad instance, you are out of luck. Monad requires a type constructor of kind * -> *, which means we are attempting to do something like this (in pseudo-code):
instance Monad m => Monad (/\a -> e -> m a) where
-- ...
where /\ stands for type-level lambda. However, the closest thing we can get to a type level lambda is a type synonym (which must be fully applied before we can make type class instances, so no luck here) or a type family (which cannot be used as an argument to type class either). Using something like (->) e . m leads to newtype again.
Let's first rewrite the body of
r :: String -> IO ()
r = do
p1
p2
using (>>),
r = p1 >> p2
so p1 must have type m a for some Monad m, and p2 must have type m b for the same m.
Now,
p1, p2 :: String -> IO ()
and the top-level type constructor in that is the function arrow (->). Therefore the Monad used in r must be
(->) String
The Monad instance for (->) e [aka the reader monad], is
instance Monad ((->) e) where
-- return :: a -> (e -> a)
return = const
-- (>>=) :: (e -> a) -> (a -> (e -> b)) -> (e -> b)
f >>= g = \x -> g (f x) x
and consequently,
p1 >> p2 = p1 >>= \_ -> p2
= \x -> (\_ -> p2) (p1 x) x -- apply (\_ -> p2) to (p1 x)
= \x -> p2 x -- eta-reduce
= p2
so that was just a complicated way to write
r = p2
For r you used (->) String (IO ()) which is a Monad ((->) String) that returns a value of type IO ().
You did NOT use a ReaderT or any monad transformer. You used a monad that returns a different monad. It accidentally compiled and ran, almost doing what you expected.
You need to use runReaderT and lift (or liftIO) to achieve the r that I think you are trying to make.
You left off the argument when you invoke p1 and p2 in r. What you wrote is then interpreted as pointfree notation, so only the second IO action gets an argument. This works:
r :: String -> IO ()
r x = do
p1 x
p2 x
To understand why this is happening, consider that what you originally wrote is equivalent to
r = p1 >> p2
The compiler interprets that as something like
r x = (p1 >> p2) x
Which isn't what you want.

Resources