-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
instance MonadUnliftIO Ctl #1
Comments
(I assume you mean No - because you'd need instance MonadUnliftIO Ctl where
withRunInIO f = Ctl $ fmap Pure $ f \(Ctl m) -> _what
instance MonadBaseControl IO Ctl where
type StM Ctl a = Result a
liftBaseWith f = Ctl $ fmap Pure $ f unCtl
restoreM = Ctl . pure though I'd rather not have it because it certainly would cause all kinds of semantic problems. |
Right. That's what I thought :( That makes it unviable for real-world usage to me.
True, if the yield or raise can be lost, we're back to square one. Ok, thanks for exploring this area. I have a feeling that if/when proper support for delimited continuations in merged into GHC, this shouldn't be a problem anymore since with the low-level support you can manipulate the call stack and effectively bypass the type system, so it should be possible to write I'm wondering about this since while I don't personally need the
cc @lexi-lambda - my current assumption is that once your patch for delimited continuations is merged, |
Alexis and I discussed the
at which point you get an In other words, the interaction of
means the |
@arybczak Note that IO-native prompt tag $ do
forkIO $ do
...
control tag ...
-- GHC.Exts.control0#: no matching prompt in the current continuation ...which is a good thing because such behavior can't possibly be well defined, but also a bad thing because we haven't really figured out how to rule them out in an effect system. One way could be to only allow embedding first-order |
Ideally I'd like to use So this would only be a problem if someone spawns threads inside the My understanding of delimited continuations is still shallow at best, so this all might not work the way I think it does. |
Yes, I think that kind of check is possible. When an effect is handled, you can just put the current Also this check doesn't help us deal with when the user insists to unlift an Regarding mutable |
On another note, embedding If we only enable |
FYI, I experimented with delimited continuations since https://gitlab.haskell.org/ghc/ghc/-/merge_requests/7942 was merged and I'm slightly confused. I got the basic version of the NonDet working, but I'm clearly missing something. Consider this: {-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# OPTIONS_GHC -Wall #-}
module Main where
import Control.Applicative
import Control.Exception
import Data.IORef
import GHC.Exts
import GHC.IO
main :: IO ()
main = do
v <- newIORef (0::Int)
r <- runNonDet @[] $ \tag -> do
bracket_ (modifyIORef' v succ) (modifyIORef' v pred) $ do
x <- choose tag (pure True) (pure False)
y <- choose tag (pure 'a') (pure 'b')
pure (x, y)
putStrLn $ "r: " ++ show r
putStrLn . ("v: " ++) . show =<< readIORef v
----------------------------------------
runNonDet :: Alternative f => (PromptTag (f r) -> IO r) -> IO (f r)
runNonDet f = do
tag <- newPromptTag
prompt tag (pure <$> f tag)
choose :: Alternative f => PromptTag (f r) -> IO a -> IO a -> IO a
choose tag ma mb = control0 tag $ \k -> do
fa <- prompt tag $ k ma
fb <- prompt tag $ k mb
pure $ fa <|> fb
----------------------------------------
data PromptTag a = PromptTag (PromptTag# a)
newPromptTag :: IO (PromptTag a)
newPromptTag = IO $ \s -> case newPromptTag# s of
(# s', tag #) -> (# s', PromptTag tag #)
prompt :: PromptTag a -> IO a -> IO a
prompt (PromptTag tag) (IO m) = IO $ prompt# tag m
control0 :: PromptTag a -> ((IO b -> IO a) -> IO a) -> IO b
control0 (PromptTag tag) f =
IO . control0# tag $ \k -> case f $ \(IO a) -> IO (k a) of IO b -> b and it kinda works, but not quite as I would expect it to. It produces
So you get multiple results, but there is a problem with Which I find confusing, because the |
I believe the continuation only captures everything from the |
Please read the documentation for those primops before using them—using them with arbitrary |
I believe @arybczak In fact, in the |
No, it is not. A version of |
Well, that's true! I only meant that using |
I see, that makes sense.
I did read it (though can't say the same about fully understanding it apparently). The program I included is a simplification of the program from your action :: (NonDet :< es, Writer (Sum Int) :< es) => Eff es ((Sum Int), Bool)
action = listen (add 1 *> (add 2 $> True <|> add 3 $> False))
where add = tell . Sum @Int
main :: IO ()
main = do
print $ run (runNonDetAll @[] $ runWriter @(Sum Int) action) The problem I had when I tried to translate it to But even if it didn't use I was hoping both |
Yes, this strategy just doesn’t work when computations can be reentrant (which capturing the continuation allows), which is why supporting all these things together is hard. |
Indeed - you would need to implement it according to (I should say that I've been picking up all my effect system knowledge along the course of a few months - so if what I say now conflicts with what I said weeks ago, I apologize) |
Can it be written? 🤔
The text was updated successfully, but these errors were encountered: