
I'm looking for pointers on how to do something. What I'm trying to do: I want to define a newtype wrapper for database connections with a phantom type to control whether the connection is read-only or read-write. So I have: newtype Conn a = Conn { unConn :: Connection } data ReadOnly = ReadOnly data ReadWrite = ReadWrite -- Simplifying here openConn :: MonadIO m => a -> Conn a query :: (MonadIO m, ToRow r, FromRow s) => Conn a -> Query -> r -> m [s] execute :: (MonadIO m, ToRow r) => Conn a -> Query -> r -> m Int64 But I want to be able to restrict the type a to be either ReadOnly or ReadWrite. Solutions I've come up with so far are: - Don't bother. Later function calls put enough of constraint on the types that it isn't really necessary. Or rather, ReadWrite is necessary, but ReadOnly isn't. - Define some type class that ReadWrite and ReadOnly implement, but don't export the body of the typeclass from the module, preventing other people from implementing it for other types. - Some sort of trickiness with closed type families that I haven't worked out yet. Are their alternatives I haven't considered yet? Thanks. Brian

On Tue, Feb 27, 2018 at 02:53:33PM +0000, Brian Hurt wrote:
I'm looking for pointers on how to do something. What I'm trying to do: I want to define a newtype wrapper for database connections with a phantom type to control whether the connection is read-only or read-write. So I have:
newtype Conn a = Conn { unConn :: Connection }
data ReadOnly = ReadOnly
data ReadWrite = ReadWrite
-- Simplifying here openConn :: MonadIO m => a -> Conn a
query :: (MonadIO m, ToRow r, FromRow s) => Conn a -> Query -> r -> m [s]
execute :: (MonadIO m, ToRow r) => Conn a -> Query -> r -> m Int64
But I want to be able to restrict the type a to be either ReadOnly or ReadWrite. Solutions I've come up with so far are: [...] Are their alternatives I haven't considered yet?
Have you considered {-# LANGUAGE DataKinds #-} data Read = ReadOnly | ReadWrite ?

No, and thank you and astrohavoc@gmail.com for pointing it out. I was going "There *has to be* a better solution to this". On Tue, Feb 27, 2018 at 3:10 PM, Tom Ellis < tom-lists-haskell-cafe-2013@jaguarpaw.co.uk> wrote:
On Tue, Feb 27, 2018 at 02:53:33PM +0000, Brian Hurt wrote:
I'm looking for pointers on how to do something. What I'm trying to do: I want to define a newtype wrapper for database connections with a phantom type to control whether the connection is read-only or read-write. So I have:
newtype Conn a = Conn { unConn :: Connection }
data ReadOnly = ReadOnly
data ReadWrite = ReadWrite
-- Simplifying here openConn :: MonadIO m => a -> Conn a
query :: (MonadIO m, ToRow r, FromRow s) => Conn a -> Query -> r -> m [s]
execute :: (MonadIO m, ToRow r) => Conn a -> Query -> r -> m Int64
But I want to be able to restrict the type a to be either ReadOnly or ReadWrite. Solutions I've come up with so far are: [...] Are their alternatives I haven't considered yet?
Have you considered
{-# LANGUAGE DataKinds #-}
data Read = ReadOnly | ReadWrite
? _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

You can use DataKinds extension and define a singleton type for
ReadOnly/WriteOnly. The code roughly looks like:
data ReadWrite = ReadOnly | WriteOnly
newtype Conn (a :: ReadWrite) = ...
openConn :: MonadIO m => Sing a -> m (Conn a)
In the implementation of openConn you can pattern match on Sing a and
recover ReadOnly/WriteOnly both on term/type level. The singletons package
provide utilities to ease writing this style of code.
On Tue, Feb 27, 2018, 10:56 PM Brian Hurt
I'm looking for pointers on how to do something. What I'm trying to do: I want to define a newtype wrapper for database connections with a phantom type to control whether the connection is read-only or read-write. So I have:
newtype Conn a = Conn { unConn :: Connection }
data ReadOnly = ReadOnly
data ReadWrite = ReadWrite
-- Simplifying here openConn :: MonadIO m => a -> Conn a
query :: (MonadIO m, ToRow r, FromRow s) => Conn a -> Query -> r -> m [s]
execute :: (MonadIO m, ToRow r) => Conn a -> Query -> r -> m Int64
But I want to be able to restrict the type a to be either ReadOnly or ReadWrite. Solutions I've come up with so far are:
- Don't bother. Later function calls put enough of constraint on the types that it isn't really necessary. Or rather, ReadWrite is necessary, but ReadOnly isn't.
- Define some type class that ReadWrite and ReadOnly implement, but don't export the body of the typeclass from the module, preventing other people from implementing it for other types.
- Some sort of trickiness with closed type families that I haven't worked out yet.
Are their alternatives I haven't considered yet?
Thanks.
Brian
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (3)
-
Brian Hurt
-
Shao Cheng
-
Tom Ellis