Corentin Dupont | 1 Feb 16:55 2014
Picon

DSLs and heterogeous lists

Hi again,
I have a game in which the user can create/write/read variables, using a small DSL. The type of the variable created can be whatever chooses the user, so I'm using existential types to store those variables in a heterogeneous list.
This works fine, but the problem is that the "Typeable" class tag leaks into the DSL... The question is, how to get rid of it?

> This is literate Haskell
> {-# LANGUAGE GADTs, ScopedTypeVariables  #-}
> module DSLClass where
> import Control.Monad
> import Control.Monad.State
> import Data.Typeable
>


This is the (simplified) DSL. With it you can read a variable stored in the game state (creation/writing is not shown).
How can we get rid of the "Typeable a" in the ReadFirstVar constructor?

> -- first type parameter is used to track effects
> data Exp a where
>   ReadFirstVar :: (Typeable a) => Exp a           <----- Ugly
>   Return       :: a -> Exp a
>   Bind         :: Exp a -> (a -> Exp b) -> Exp b


This is the definition of a variable. The type is unknow, so I use existantial types.

> data Var = forall a . (Typeable a) => Var { v :: a}


This game state. It holds the heterogenous list.

> data Game = Game { variables :: [Var]}

The evaluation of "Exp" can be:

> eval :: Exp a -> State Game a
> eval ReadFirstVar  = do
>   (Game ((Var v):vs)) <- get
>   case cast v of
>      Just val -> return val
>      Nothing -> error "no cast"
> eval (Bind exp f) = do
>   a <- eval exp
>   eval (f a)


As you can see, I'm obliged to cast the variable type to match it with the expression's type. Is that the right place to do it?

Thanks!!
Corentin
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Richard Eisenberg | 1 Feb 19:02 2014

Re: DSLs and heterogeous lists

This seems reasonable to me. What's ugly about it? As I see it, casting really is necessary, because there's no way to know whether the type of the head variable in the list is correct without it.

Richard

On Feb 1, 2014, at 10:55 AM, Corentin Dupont <corentin.dupont <at> gmail.com> wrote:

Hi again,
I have a game in which the user can create/write/read variables, using a small DSL. The type of the variable creat ed can be whatever chooses the user, so I'm using existential types to store those variables in a heterogeneous list.
This works fine, but the problem is that the "Typeable" class tag leaks into the DSL... The question is, how to get rid of it?

> This is literate Haskell
> {-# LANGUAGE GADTs, ScopedTypeVariables  #-}
> module DSLClass where
> import Control.Monad
> import Control.Monad.State
> import Data.Typeable
>


This is the (simplified) DSL. With it you can read a variable stored in the game state (creation/writing is not shown).
How can we get rid of the "Typeable a" in the ReadFirstVar constructor?

> -- first type parameter is used to track effects
> data Exp a where
>   ReadFirstVar :: (Typeable a) => Exp a           <----- Ugly
>   Return       :: a -> Exp a
>   Bind         :: Exp a -> (a -> Exp b) -> Exp b


This is the definition of a variable. The type is unknow, so I use existantial types.

> data Var = forall a . (Typeable a) => Var { v :: a}


This game state. It holds the heterogenous list.

> data Game = Game { variables :: [Var]}

The evaluation of "Exp" can be:

> eval :: Exp a -> State Game a
> eval ReadFirstVar  = do
>   (Game ((Var v):vs)) <- get
>   case cast v of
>      Just val -> return val
>      Nothing -> error "no cast"
> eval (Bind exp f) = do
>   a <- eval exp
>   eval (f a)


As you can see, I'm obliged to cast the variable type to match it with the expression's type. Is that the right place to do it?

Thanks!!
Corentin
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Corentin Dupont | 1 Feb 19:51 2014
Picon

Re: DSLs and heterogeous lists

Ugly, maybe not, but I read somewhere that the class restriction should be on the functions definitions than in the datatype definition... That is, the datatype is usually defined without class restriction, instead the necessary class restriction is added latter on in the functions signatures that work on that datatype.


On Sat, Feb 1, 2014 at 7:02 PM, Richard Eisenberg <eir <at> cis.upenn.edu> wrote:
This seems reasonable to me. What's ugly about it? As I see it, casting really is necessary, because there's no way to know whether the type of the head variable in the list is correct without it.

Richard

On Feb 1, 2014, at 10:55 AM, Corentin Dupont <corentin.dupont <at> gmail.com> wrote:

Hi again,
I have a game in which the user can create/write/read variables, using a small DSL. The type of the variable created can be whatever chooses the user, so I'm using existential types to store those variables in a heterogeneous list.
This works fine, but the problem is that the "Typeable" class tag leaks into the DSL... The question is, how to get rid of it?

> This is literate Haskell
> {-# LANGUAGE GADTs, ScopedTypeVariables  #-}
> module DSLClass where
> import Control.Monad
> import Control.Monad.State
> import Data.Typeable
>


This is the (simplified) DSL. With it you can read a variable stored in the game state (creation/writing is not shown).
How can we get rid of the "Typeable a" in the ReadFirstVar constructor?

> -- first type parameter is used to track effects
> data Exp a where
>   ReadFirstVar :: (Typeable a) => Exp a           <----- Ugly
>   Return       :: a -> Exp a
>   Bind         :: Exp a -> (a -> Exp b) -> Exp b


This is the definition of a variable. The type is unknow, so I use existantial types.

> data Var = forall a . (Typeable a) => Var { v :: a}


This game state. It holds the heterogenous list.

> data Game = Game { variables :: [Var]}

The evaluation of "Exp" can be:

> eval :: Exp a -> State Game a
> eval ReadFirstVar  = do
>   (Game ((Var v):vs)) <- get
>   case cast v of
>      Just val -> return val
>      Nothing -> error "no cast"
> eval (Bind exp f) = do
>   a <- eval exp
>   eval (f a)


As you can see, I'm obliged to cast the variable type to match it with the expression's type. Is that the right place to do it?

Thanks!!
Corentin
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Richard Eisenberg | 1 Feb 20:09 2014

Re: DSLs and heterogeous lists

There are three (relevant) places a constraint could go:

data Typeable a => Exp a = ...  -- (1)

data Exp a where
  ReadFirstVar :: Typeable a => Exp a        -- (2)

eval :: Typeable a => Exp a -> ... -- (3)

You're currently doing (2). When people talk about not putting constraints on datatypes, I imagine they're talking about (1), which is indeed a bad idea. Using (1) essentially buys you nothing -- you would still still a constraint like (3) to work with the type declared in (1). So, the real choice is between (2) and (3). Each of these has its advantages. (2) essentially says that the data stored by the ReadFirstVar constructor is the type of the expression. (3) essentially says that any caller of `eval` also has to pass in the desired type for the expression. Without seeing more code, it's hard to know what's better in your scenario.

But, my bottom line is that the advice you've read probably pertains to (1), not (2) -- it's not saying that what you've done is bad.

Richard

On Feb 1, 2014, at 1:51 PM, Corentin Dupont <corentin.dupont <at> gmail.com> wrote:

Ugly, maybe not, but I read somewhere that the class restriction should be on the functions definitions than in the datatype definition... That is, the datatype is usually defined without class restriction, instead the necessary class restriction is added latter on in the functions signatures that work on that datatype.


On Sat, Feb 1, 2014 at 7:02 PM, Richard Eisenberg <eir <at> cis.upenn.edu> wrote:
This seems reasonable to me. What's ugly about it? As I see it, casting really is necessary, because there's no way to know whether the type of the head variable in the list is correct without it.

Richard

On Feb 1, 2014, at 10:55 AM, Corentin Dupont <corentin.dupont <at> gmail.com> wrote:

Hi again,
I have a game in which the user can create/write/read variables, using a small DSL. The type of the variable created can be whatever chooses the user, so I'm using existential types to store those variables in a heterogeneous list.
This works fine, but the problem is that the "Typeable" class tag leaks into the DSL... The question is, how to get rid of it?

> This is literate Haskell
> {-# LANGUAGE GADTs, ScopedTypeVariables  #-}
> module DSLClass where
> import Control.Monad
> import Control.Monad.State
> import Data.Typeable
>


This is the (simplified) DSL. With it you can read a variable stored in the game state (creation/writing is not shown).
How can we get rid of the "Typeable a" in the ReadFirstVar constructor?

> -- first type parameter is used to track effects
> data Exp a where
>   ReadFirstVar :: (Typeable a) => Exp a           <----- Ugly
>   Return       :: a -> Exp a
>   Bind         :: Exp a -> (a -> Exp b) -> Exp b


This is the definition of a variable. The type is unknow, so I use existantial types.

> data Var = forall a . (Typeable a) => Var { v :: a}


This game state. It holds the heterogenous list.

> data Game = Game { variables :: [Var]}

The evaluation of "Exp" can be:

> eval :: Exp a -> State Game a
> eval ReadFirstVar  = do
>   (Game ((Var v):vs)) <- get
>   case cast v of
>      Just val -> return val
>      Nothing -> error "no cast"
> eval (Bind exp f) = do
>   a <- eval exp
>   eval (f a)


As you can see, I'm obliged to cast the variable type to match it with the expression's type. Is that the right place to do it?

Thanks!!
Corentin
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe



_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Gmane