Type level variants

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Type level variants

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.
Reply | Threaded
Open this post in threaded view
|

Re: Type level variants

Tom Ellis
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.
Reply | Threaded
Open this post in threaded view
|

Re: Type level variants

Shao Cheng
In reply to this post by Brian Hurt
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 <[hidden email]> 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:

- 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.

_______________________________________________
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.
Reply | Threaded
Open this post in threaded view
|

Re: Type level variants

Brian Hurt
In reply to this post by Tom Ellis
No, and thank you and [hidden email] 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 <[hidden email]> 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.


_______________________________________________
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.