[Haskell-cafe] Eliminating phantom type

Timotej Tomandl timotej.tomandl at gmail.com
Sat Apr 8 04:03:00 UTC 2017


Hi,
I have stumbled upon the Control-Monad-ST2 package by Kevin Backhouse, I
have decided to expand the code with a run function and replace IO with ST
s; and as of now I have removed the functions working on arrays and
conversion to IO for the sake of simplicity. Here is the code in its
modified form with newtype wrappers removed:

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DeriveFunctor #-}
-- Copyright 2013 Kevin Backhouse.
-- Copyright 2017 Timotej Tomandl. Modifications

import Data.STRef
import Control.Monad.ST
import Control.Applicative
import Control.Monad

newtype ST2 r w s a = ST2 { unwrapST2 :: ST s a }
    deriving (Functor)
instance Monad (ST2 r w s) where
  return x = ST2 $ return x
  (ST2 m) >>= f = ST2 $ do
        x <- m
        unwrapST2 (f x)
instance Applicative (ST2 r w s) where
  pure = return
  (<*>) = ap

-- | This function checks that the sub-computation is polymorphic in
-- both type parameters. This means that the sub-computation does not
-- read or write any state from the enclosing context.
{-# INLINE pureST2 #-}
pureST2 :: (forall r w. ST2 r w s a) -> ST2 r' w' s a
pureST2 m = m

-- | This function checks that the computation is polymorphic in
-- both parameters and then returns a pure value
{-# INLINE runST2 #-}
runST2 :: (forall r w s. ST2 r w s a) -> a
runST2 m=runST $ unwrapST2 m

-- | This function checks that the sub-computation is polymorphic in
-- the @w@ type parameter. This means that the sub-computation does
-- not write any state from the enclosing context (but read-only
-- operations are permitted).
{-# inline readOnlyST2 #-}
readOnlyST2 :: (forall w. ST2 r w s a) -> ST2 r w' s a
readOnlyST2 m = m

-- | Mutable reference. 'ST2Ref' is actually just a newtype of an
-- 'STRef', but the @r@ and @w@ type parameters allow the read and
-- write dependencies to be tracked by the type system.
newtype ST2Ref r w s a = ST2Ref (STRef s a)

-- | Create a new reference. The @r@ and @w@ type parameters of the
-- reference are unified with the 'ST2' monad to indicate that new
-- state is created in the enclosing context.
{-# INLINE newST2Ref #-}
newST2Ref :: a -> ST2 r w s (ST2Ref r w s a)
newST2Ref x = ST2 $ do
    r <- newSTRef x >>= \ var -> return var
    return (ST2Ref r)

-- | Read a reference. The @w@ type parameter of the reference is not
-- unified with the 'ST2' monad to indicate that this access is
-- read-only.
{-# INLINE readST2Ref #-}
readST2Ref :: ST2Ref r w s a -> ST2 r w' s a
readST2Ref (ST2Ref r) = ST2 $ readSTRef r

-- | Write to a reference. The @w@ type parameter of the reference is
-- unified with the 'ST2' monad to indicate that state is written in
-- the enclosing context.
{-# INLINE writeST2Ref #-}
writeST2Ref :: ST2Ref r w s a -> a -> ST2 r w s ()
writeST2Ref (ST2Ref r) x = ST2 $ writeSTRef r x

-- | Modify a reference.
{-# INLINE modifyST2Ref #-}
modifyST2Ref :: ST2Ref r w s a -> (a -> a) -> ST2 r w s ()
modifyST2Ref (ST2Ref r) f = ST2 $ modifySTRef r f

But as you can see, now all my types got tainted by s even though sharing
the same r or w implies sharing the same s. Is there a way how to hide s
from the type signatures, but still preserve an ability to write runST2
without resorting to IO/RealWorld? I have tried writing such a function and
failed.

Timotej Tomandl
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20170408/4d7c5c63/attachment-0001.html>


More information about the Haskell-Cafe mailing list