I can't grasp the correct way of interrupting lengthy pure computation on SIGINT signal.
In the simple example below, I have slowFib function that simulates lengthy computation. When it is run just in IO monad I can terminate it with C-c (using async to spawn worker).
However, when I put computation inside MonadState, MonadIO stack it no longer work... On the other hand, simple threadDelay in the same stack still can be terminated.
The code is following:
{-# LANGUAGE FlexibleContexts #-}
module Main where
import Data.Monoid
import Control.DeepSeq
import Control.Concurrent
import Control.Concurrent.Async
import Control.Monad.State
-- import Control.Monad.State.Strict
import System.Posix.Signals
slowFib :: Integer -> Integer
slowFib 0 = 0
slowFib 1 = 1
slowFib n = slowFib (n - 2 ) + slowFib (n - 1)
data St = St { x :: Integer } deriving (Show)
stateFib :: (MonadState St m, MonadIO m) => Integer -> m Integer
stateFib n = do
let f = slowFib n
modify $ \st -> st{x=f}
return f
stateWait :: (MonadState St m, MonadIO m) => Integer -> m Integer
stateWait n = do
liftIO $ threadDelay 5000000
return 41
interruptable n act = do
putStrLn $ "STARTING EVALUATION: " <> n
e <- async act
installHandler sigINT (Catch (cancel e)) Nothing
putStrLn "WAITING FOR RESULT"
waitCatch e
main = do
let s0 = St 0
r <- interruptable "slowFib" $ do
let f = slowFib 41
f `deepseq` return ()
return f
r <- interruptable "threadDelay in StateT" $ runStateT (stateWait 41) s0
putStrLn $ show r
r <- interruptable "slowFib in StateT" $ runStateT (stateFib 41) s0
putStrLn $ show r
I suspected that it has something to do with lazy evaluation. I already figured out that in the first example (with just the IO monad) I have to force the result. Otherwise async computation just returns a thunk.
However all my attempts to do something analogous in MonadState failed. Anyway, it seems to be more complicated, since async thread does not return immediately. It waits until the result is computed. For some reason I just cannot terminate it when the pure computation is "blocking".
Any clues?
PS. My use case is too add ability to abort computation in custom Jupyter kernel made using jupyter package. Functions evaluating user input are exactly in MonadState and MonadIO.
The computation seems to be blocked on putStrLn $ show r, i.e. outside the interruptable function. Note that stateFib doesn't force the result, so the async exits almost immediately. The whole work is delayed until putStrLn tries to print the result. Try to force the computation earlier:
stateFib :: (MonadState St m, MonadIO m) => Integer -> m Integer
stateFib n = do
let f = slowFib n
modify $ \st -> st{x=f}
f `seq` return f
Related
I'm writing some code (around card-playing strategies) that uses State and recursion together. Perhaps this part doesn't need to actually (it already feels clumsy to me, even as a relative beginner), but there are other parts that probably do so my general question stands...
My initial naive implementation is entirely deterministic (the choice of bid is simply the first option provided by the function validBids):
bidOnRound :: (DealerRules d) => d -> NumCards -> State ([Player], PlayerBids) ()
bidOnRound dealerRules cardsThisRound = do
(players, bidsSoFar) <- get
unless (List.null players) $ do
let options = validBids dealerRules cardsThisRound bidsSoFar
let newBid = List.head $ Set.toList options
let p : ps = players
put (ps, bidsSoFar ++ [(p, newBid)])
bidOnRound dealerRules cardsThisRound
And I call it from:
playGame :: (DealerRules d, ScorerRules s) => d -> s -> StateT Results IO ()
...
let (_, bidResults) = execState (bidOnRound dealerRules cardsThisRound) (NonEmpty.toList players, [])
Now I'm aware that I need to bring randomness into this and several other parts of the code. Not wanting to litter IO everywhere, nor pass round random seeds manually all the time, I feel I should be using MonadRandom or something. A library I'm using uses it to good effect. Is this a wise choice?
Here's what I tried:
bidOnRound :: (DealerRules d, RandomGen g) => d -> NumCards -> RandT g (State ([Player], PlayerBids)) ()
bidOnRound dealerRules cardsThisRound = do
(players, bidsSoFar) <- get
unless (List.null players) $ do
let options = Set.toList $ validBids dealerRules cardsThisRound bidsSoFar
rnd <- getRandomR (0 :: Int, len options - 1)
let newBid = options List.!! rnd
let p : ps = players
put (ps, bidsSoFar ++ [(p, newBid)])
bidOnRound dealerRules cardsThisRound
but I'm uncomfortable already, plus can't work out how to call this, e.g. using evalRand in combination with execState etc. The more I read on MonadRandom, RandGen and mtl vs others, the less sure I am of what I'm doing...
How should I neatly combine Randomness and State and how do I call these properly?
Thanks!
EDIT: for reference, full current source on Github.
Well how about an example to help you out. Since you didn't post a full working code snippet I'll just replace a lot of your operations and show how the monads can be evaluated:
import Control.Monad.Trans.State
import Control.Monad.Random
import System.Random.TF
bidOnRound :: (RandomGen g) => Int -> RandT g (State ([Int], Int)) ()
bidOnRound i =
do rand <- getRandomR (10,20)
s <- lift $ get
lift $ put ([], i + rand + snd s)
main :: IO ()
main =
do g <- newTFGen
print $ flip execState ([],1000) $ evalRandT (bidOnRound 100) g
The thing to note here is you "unwrap" the outer monad first. So if you have RandT (StateT Reader ...) ... then you run RandT (ex via evalRandT or similar) then the state then the reader. Secondly, you must lift from the outer monad to use operations on the inner monad. This might seem clumsy and that is because it is horribly clumsy.
The best developers I know - those whose code I enjoy looking at and working with - extract monad operations and provide an API with all the primitives complete so I don't need to think about the structure of the monad while I'm thinking about the structure of the logic I'm writing.
In this case (it will be slightly contrived since I wrote the above without any application domain, rhyme or reason) you could write:
type MyMonad a = RandT TFGen (State ([Int],Int)) a
runMyMonad :: MyMonad () -> IO Int
runMyMonad f =
do g <- newTFGen
pure $ snd $ flip execState ([],1000) $ evalRandT f g
With the Monad defined as a simple alias and execution operation the basic functions are easier:
flipCoin :: MyMonad Int
flipCoin = getRandomR (10,20)
getBaseValue :: MyMonad Int
getBaseValue = snd <$> lift get
setBaseValue :: Int -> MyMonad ()
setBaseValue v = lift $ state $ \s -> ((),(fst s, v))
With that leg-work out of the way, which is usually a minor part of making a real application, the domain specific logic is easier to write and certainly easier to read:
bidOnRound2 :: Int -> MyMonad ()
bidOnRound2 i =
do rand <- flipCoin
old <- getBaseValue
setBaseValue (i + rand + old)
main2 :: IO ()
main2 = print =<< runMyMonad (bidOnRound2 100)
I'm trying to work out if it's possible to write an abstraction for the following situation. Suppose I have a type a with function a -> m Bool e.g. MVar Bool and readMVar. To abstract this concept out I create a newtype wrapper for the type and its function:
newtype MPredicate m a = MPredicate (a,a -> m Bool)
I can define a fairly simple operation like so:
doUnless :: (Monad m) => Predicate m a -> m () -> m ()
doUnless (MPredicate (a,mg)) g = mg a >>= \b -> unless b g
main = do
b <- newMVar False
let mpred = MPredicate (b,readMVar)
doUnless mpred (print "foo")
In this case doUnless would print "foo". Aside: I'm not sure whether a type class might be more appropriate to use instead of a newtype.
Now take the code below, which outputs an incrementing number then waits a second and repeats. It does this until it receives a "turn off" instruction via the MVar.
foobar :: MVar Bool -> IO ()
foobar mvb = foobar' 0
where
foobar' :: Int -> IO ()
foobar' x = readMVar mvb >>= \b -> unless b $ do
let x' = x + 1
print x'
threadDelay 1000000
foobar' x'
goTillEnter :: MVar Bool -> IO ()
goTillEnter mv = do
_ <- getLine
_ <- takeMVar mv
putMVar mv True
main = do
mvb <- newMVar False
forkIO $ foobar mvb
goTillEnter mvb
Is it possible to refactor foobar so that it uses MPredicate and doUnless?
Ignoring the actual implementation of foobar' I can think of a simplistic way of doing something similar:
cycleUnless :: x -> (x -> x) -> MPredicate m a -> m ()
cycleUnless x g mp = let g' x' = doUnless mp (g' $ g x')
in g' $ g x
Aside: I feel like fix could be used to make the above neater, though I still have trouble working out how to use it
But cycleUnless won't work on foobar because the type of foobar' is actually Int -> IO () (from the use of print x').
I'd also like to take this abstraction further, so that it can work threading around a Monad. With stateful Monads it becomes even harder. E.g.
-- EDIT: Updated the below to show an example of how the code is used
{- ^^ some parent function which has the MVar ^^ -}
cycleST :: (forall s. ST s (STArray s Int Int)) -> IO ()
cycleST sta = readMVar mvb >>= \b -> unless b $ do
n <- readMVar someMVar
i <- readMVar someOtherMVar
let sta' = do
arr <- sta
x <- readArray arr n
writeArray arr n (x + i)
return arr
y = runSTArray sta'
print y
cycleST sta'
I have something similar to the above working with RankNTypes. Now there's the additional problem of trying to thread through the existential s, which is not likely to type check if threaded around through an abstraction the likes of cycleUnless.
Additionally, this is simplified to make the question easier to answer. I also use a set of semaphores built from MVar [MVar ()] similar to the skip channel example in the MVar module. If I can solve the above problem I plan to generalize the semaphores as well.
Ultimately this isn't some blocking problem. I have 3 components of the application operating in a cycle off the same MVar Bool but doing fairly different asynchronous tasks. In each one I have written a custom function that performs the appropriate cycle.
I'm trying to learn the "don't write large programs" approach. What I'd like to do is refactor chunks of code into their own mini libraries so that I'm not building a large program but assembling lots of small ones. But so far this particular abstraction is escaping me.
Any thoughts on how I might go about this are very much appreciated!
You want to cleanly combine a stateful action having side effects, a delay, and an independent stopping condition.
The iterative monad transformer from the free package can be useful in these cases.
This monad transformer lets you describe a (possibly nonending) computation as a series of discrete steps. And what's better, it let's you interleave "stepped" computations using mplus. The combined computation stops when any of the individual computations stops.
Some preliminary imports:
import Data.Bool
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Iter (delay,untilJust,IterT,retract,cutoff)
import Control.Concurrent
Your foobar function could be understood as a "sum" of three things:
A computation that does nothing but reading from the MVar at each step, and finishes when the Mvar is True.
untilTrue :: (MonadIO m) => MVar Bool -> IterT m ()
untilTrue = untilJust . liftM guard . liftIO . readMVar
An infinite computation that takes a delay at each step.
delays :: (MonadIO m) => Int -> IterT m a
delays = forever . delay . liftIO . threadDelay
An infinite computation that prints an increasing series of numbers.
foobar' :: (MonadIO m) => Int -> IterT m a
foobar' x = do
let x' = x + 1
liftIO (print x')
delay (foobar' x')
With this in place, we can write foobar as:
foobar :: (MonadIO m) => MVar Bool -> m ()
foobar v = retract (delays 1000000 `mplus` untilTrue v `mplus` foobar' 0)
The neat thing about this is that you can change or remove the "stopping condition" and the delay very easily.
Some clarifications:
The delay function is not a delay in IO, it just tells the iterative monad transformer to "put the argument in a separate step".
retract brings you back from the iterative monad transformer to the base monad. It's like saying "I don't care about the steps, just run the computation". You can combine retract with cutoff if you want to limit the maximum number of iterations.
untilJustconverts a value m (Maybe a) of the base monad into a IterT m a by retrying in each step until a Just is returned. Of course, this risks non-termination!
MPredicate is rather superfluous here; m Bool can be used instead. The monad-loops package contains plenty of control structures with m Bool conditions. whileM_ in particular is applicable here, although we need to include a State monad for the Int that we're threading around:
import Control.Monad.State
import Control.Monad.Loops
import Control.Applicative
foobar :: MVar Bool -> IO ()
foobar mvb = (`evalStateT` (0 :: Int)) $
whileM_ (not <$> lift (readMVar mvb)) $ do
modify (+1)
lift . print =<< get
lift $ threadDelay 1000000
Alternatively, we can use a monadic version of unless. For some reason monad-loops doesn't export such a function, so let's write it:
unlessM :: Monad m => m Bool -> m () -> m ()
unlessM mb action = do
b <- mb
unless b action
It's somewhat more convenient and more modular in a monadic setting, since we can always go from a pure Bool to m Bool, but not vice versa.
foobar :: MVar Bool -> IO ()
foobar mvb = go 0
where
go :: Int -> IO ()
go x = unlessM (readMVar mvb) $ do
let x' = x + 1
print x'
threadDelay 1000000
go x'
You mentioned fix; sometimes people indeed use it for ad-hoc monadic loops, for example:
printUntil0 :: IO ()
printUntil0 =
putStrLn "hello"
fix $ \loop -> do
n <- fmap read getLine :: IO Int
print n
when (n /= 0) loop
putStrLn "bye"
With some juggling it's possible to use fix with multi-argument functions. In the case of foobar:
foobar :: MVar Bool -> IO ()
foobar mvb = ($(0 :: Int)) $ fix $ \loop x -> do
unlessM (readMVar mvb) $ do
let x' = x + 1
print x'
threadDelay 1000000
loop x'
I'm not sure what's your MPredicate is doing.
First, instead of newtyping a tuple, it's probably better to use a normal algebric data type
data MPredicate a m = MPredicate a (a -> m Bool)
Second, the way you use it, MPredicate is equivalent to m Bool.
Haskell is lazzy, therefore there is no need to pass, a function and it's argument (even though
it's usefull with strict languages). Just pass the result, and the function will be called when needed.
I mean, instead of passing (x, f) around, just pass f x
Of course, if you are not trying to delay the evaluation and really need at some point, the argument or the function as well as the result, a tuple is fine.
Anyway, in the case your MPredicate is only there to delay the function evaluation, MPredicat reduces to m Bool and doUnless to unless.
Your first example is strictly equivalent :
main = do
b <- newMVar False
unless (readMVar b) (print "foo")
Now, if you want to loop a monad until a condition is reach (or equivalent) you should have a look at the monad-loop package. What you are looking it at is probably untilM_ or equivalent.
In the following code, how can I replace put 1 with some code that insert nondeterministically 1 or 2 in the state?
import Control.Monad.List
import Control.Monad.Trans.State
test :: StateT Int [] Int
test = do
put 1
v <- get
return v
Your monad stack signature is already the correct one.
Lift a computation from the [] monad and bind to its value. This will fork the computation:
test :: StateT Int [] Int
test = do
s <- lift [1,2,3]
put s
v <- get
return v
Testing to see it works:
*Main> runStateT test 10
[(1,1),(2,2),(3,3)]
Not only there are many results, but the state gets included in the nondeterminism as well.
If test had had type ListT (State Int) Int, only the results would have been nondetermistic, the state would have been shared among all the branches in the computation:
test :: ListT (State Int) Int
test = do
s <- ListT $ return [1,2,3]
put s
v <- get
return v
The result:
*Main> runState (runListT test) 10
([1,2,3],3)
maybe you want something like this instead:
import Control.Monad.List
import Control.Monad.Trans.State
import System.Random (randomIO)
test :: StateT Int IO Int
test = do
put1 <- liftIO $ randomIO
put (if put1 then 1 else 2)
v <- get
return v
This will use the global generator to set 1 or 2 at random
i have the following set of actions:
action1 :: IO Bool
action2 :: IO Bool
action3 :: IO Bool
some actions are just composition of another actions
complexAction = do
action1
action2
action3
What i need is the construction that checks result of each action and returns False in a case of false. I can do it manually but i know for sure that haskell does have tools to get rid of that kind of boilerplate.
The simplest way is
complexAction = fmap and (sequence [action1, action2, action3])
But you could also write your own combinator to stop after the first action:
(>>/) :: Monad m => m Bool -> m Bool -> m Bool
a >>/ b = do
yes <- a
if yes then b else return False
You'd want to declare the fixity to make it associative
infixl 1 >>/
Then you can do
complexAction = action1 >>/ action2 >>/ action3
I'd suggest you to use MaybeT monad transformer instead. Using it has many advantages over just returning IO Bool:
Your actions can have different types and return values (not just true/false). If you don't need any results, just use MaybeT IO ().
Later ones can depend on results of preceding ones.
Since MaybeT produces monads that are instances of MonadPlus, you can use all monad plus operations. Namely mzero for a failed action and x mplus y, which will run y iff x fails.
A slight disadvantage is that you have to lift all IO actions to MaybeT IO. This can be solved by writing your actions as MonadIO m => ... -> m a instead of ... -> IO a.
For example:
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
-- Lift print and putStrLn
print' :: (MonadIO m, Show a) => a -> m ()
print' = liftIO . print
putStrLn' :: (MonadIO m) => String -> m ()
putStrLn' = liftIO . putStrLn
-- Add something to an argument
plus1, plus3 :: Int -> MaybeT IO Int
plus1 n = print' "+1" >> return (n + 1)
plus3 n = print' "+3" >> return (n + 3)
-- Ignore an argument and fail
justFail :: Int -> MaybeT IO a
justFail _ = mzero
-- This action just succeeds with () or fails.
complexAction :: MaybeT IO ()
complexAction = do
i <- plus1 0
justFail i -- or comment this line out <----------------<
j <- plus3 i
print' j
-- You could use this to convert your actions to MaybeT IO:
boolIOToMaybeT :: IO Bool -> MaybeT IO ()
boolIOToMaybeT x = do
r <- lift x
if r then return () else mzero
-- Or you could have even more general version that works with other
-- transformers as well:
boolIOToMaybeT' :: (MonadIO m, MonadPlus m) => IO Bool -> m ()
boolIOToMaybeT' x = do
r <- liftIO x
if r then return () else mzero
main :: IO ()
main = runMaybeT complexAction >>= print'
As Petr says, for anything but a narrow and contained case, you're almost certainly better off wiring your code for proper error handling from the outset. I know I've often regretted not doing this, condemning myself to some very tedious refactoring.
If I may, I'd like to recommend Gabriel Gonzalez's errors package, which imposes a little more coherence on Haskell's various error-handling mechanisms than has been traditional. It allows you to plumb Eithers through your code, and Either is a good type for capturing errors. (By contrast, Maybe will lose information on the error side.) Once you've installed the package, you can write things like this:
module Errors where
import Control.Error
import Data.Traversable (traverse)
data OK = OK Int deriving (Show)
action1, action2, action3 :: IO (Either String OK)
action1 = putStrLn "Running action 1" >> return (Right $ OK 1)
action2 = putStrLn "Running action 2" >> return (Right $ OK 2)
action3 = putStrLn "Running action 3" >> return (Left "Oops on 3")
runStoppingAtFirstError :: [IO (Either String OK)] -> IO (Either String [OK])
runStoppingAtFirstError = runEitherT . traverse EitherT
...with output like
*Errors> runStoppingAtFirstError [action1, action2]
Running action 1
Running action 2
Right [OK 1,OK 2]
*Errors> runStoppingAtFirstError [action1, action3, action2]
Running action 1
Running action 3
Left "Oops on 3"
(But note that the computation here stops at the first error and doesn't soldier on until the bitter end -- which might not be what you had wanted. The errors package is certainly wide-ranging enough that many other variations are possible.)
I would like to catch an exception inside runResourceT without releasing the resource, but the function catch runs the computation inside IO. Is there a way to catch an exception inside runResourceT, or what is the recommended way to refactor the code ?
Thank you for your help.
{-# LANGUAGE FlexibleContexts #-}
module Main where
import Control.Exception as EX
import Control.Monad.IO.Class
import Control.Monad.Trans.Resource
type Resource = String
allocResource :: IO Resource
allocResource = let r = "Resource"
in putStrLn (r ++ " opened.") >> return r
closeResource :: Resource -> IO ()
closeResource r = putStrLn $ r ++ " closed."
withResource :: ( MonadIO m
, MonadBaseControl IO m
, MonadThrow m
, MonadUnsafeIO m
) => (Resource -> ResourceT m a) -> m a
withResource f = runResourceT $ do
(_, r) <- allocate allocResource closeResource
f r
useResource :: ( MonadIO m
, MonadBaseControl IO m
, MonadThrow m
, MonadUnsafeIO m
) => Resource -> ResourceT m Int
useResource r = liftIO $ putStrLn ("Using " ++ r) >> return 1
main :: IO ()
main = do
putStrLn "Start..."
withResource $ \r -> do
x <- useResource r
{-- This does not compile as the catch computation runs inside IO
y <- liftIO $ EX.catch (useResource r)
(\e -> do putStrLn $ show (e::SomeException)
return 0)
--}
return ()
putStrLn "Done."
ResourceT is an instance of MonadBaseControl from the monad-control package, which is designed for lifting control structures like forkIO and catch into transformed monads.
The lifted-base package, which is built on top of monad-control, contains modules with versions of standard control structures that work in any MonadBaseControl. For exception handling, you can use the functions in the Control.Exception.Lifted module. So, just import qualified Control.Exception.Lifted as EX1 instead, and your code should work fine.
1 Note the qualified here; quite confusingly, import A as B actually imports all of the definitions in A into scope, and simply defines B as an alias for the module! You need to use qualified to ensure that the definitions are not brought into scope, and are instead accessed exclusively through the B alias.
As an alternative approach, you can use the MonadCatch instance of ResourceT, found in the exceptions package. You simply need to substitute the generalized version of catch from Control.Monad.Catch:
import Control.Monad.Catch
…
main = do
…
withResource $ \r -> do
…
y <- Control.Monad.Catch.catch (useResource r) (\e -> …)