9

Control.Monad.ST in the base package contains runST to run the strict state-transformer monad:

runST :: (forall s. ST s a) -> a

However, I need a generalized version of runST:

runSTCont :: (forall s . (forall b . ST s b -> b) -> a) -> a
runSTCont f = f $ \m -> runST $ unsafeCoerce m

My question is: Is this use of unsafeCoerse safe? (I guess so, because as I understand, the only purpose of the index s is to prevent to leak s-indexed values in the result a. The type of runSTCont cannot leak s-indexed values so it should be OK.)

Note that runST can be expressed in terms of runSTCont so runSTCont is at least as general as runST:

runST' :: (forall s. ST s a) -> a 
runST' m = runSTCont $ \runST -> runST m
  • Could you perhaps add a use-case, why you need `ruNSTCont`? – Petr Jul 13 '14 at 16:32
  • @PetrPudlák, I have a complex use case. I think I could simplify it, but the most simple use case is the implementation of `runSTCont` itself. I want to avoid comments like "this use case could be implemented also with runST". –  Jul 13 '14 at 17:52

1 Answers1

11

I don't think so:

crash = runSTCont crasher where
  crasher :: forall s. (forall b . ST s b -> b) -> Integer
  crasher go =
    let r :: forall a. STRef s (a -> a)
        r = go $ newSTRef id
    in go $ do writeSTRef r (tail . tail)
               f <- readSTRef r
               return $ f (17 :: Integer)

The problem is that Haskell lacks the value restriction.

Philip JF
  • 28,199
  • 5
  • 70
  • 77
  • 1
    Is it the problem of this particular `runSTCont` implementation, or its type in general? – Petr Jul 13 '14 at 19:24
  • 1
    @PetrPudlák it is a problem with the type in general. It would be fine if Haskell were call-by-name, but because it is implemented with call-by-need you can't generalize effectfull expressions--even if the effect (ie, heaplet you modify) is confined to a "module" which is what `runSTCont` does. – Philip JF Jul 13 '14 at 20:46
  • 2
    I would love to better understand this answer. Is there a way to change the provided type to make it safe. It seems the current one is close to allowable, but it leaks access to `unsafeCoerce`. Could this function be better implemented if you had access to the ST constructors? – J. Abrahamson Jul 14 '14 at 10:45