Figuring out if an algebraic type is enumerated through Data.Generics?

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

Figuring out if an algebraic type is enumerated through Data.Generics?

Bugzilla from alfonso.acosta@gmail.com
Hi all,


<probably_unnnecesary_background>

I'm writing a Hardware-oriented DSL deep-embedded in Haskell (similar
to Lava, for those familiar with it).

One of the goals of the language is to support polymorphic signals
(i.e. we would like to allow signals to carry values of any type,
including user-defined types)

The embedded compiler has different backends: simulation, VHDL,
graphical representation in GraphML ...

The simulation backend manages to support polymorphic signals by
forcing them to be Typeable. In that way, circuit functions, no matter
what signals they process, can be transformed to Dynamic and included
in the AST for later simulation.

The situation is more complicated for the VHDL backend. The Typeable
trick works just fine for translating a limited set of predefined
types (e.g. tuples) but not for user-defined types, since the
embedded-compiler doesn't have access to the user-defined type
declarations.

One possible solution to access the type-definition of signal values
would be constraining them to instances of Data. Then, we could use
dataTypeOf to get access to the type representation. (Another option
would be using template Haskell's reify, but I would like to avoid
that by now)

It would certainly be difficult map any Haskell type to VHDL, so, by
now we would be content to map enumerate algebraic types (i.e.
 algebraic types whose all data constructors have arity zero, e.g.
data Colors = Green | Blue | Red)

</probably_unnnecesary_background>

So, the question is. Is there a way to figure out the arity of data
constructors using Data.Generics ?

I'm totally new to generics, but (tell me if I'm wrong) it seems that
Constr doesn't hold any information about the data-constructor
arguments. Why is it so?

Do you think there is a workoaround for this problem? (maybe using
some other function from Data.Generics different to dataTypeOf?)

Thanks in advance,

Alfonso Acosta
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Figuring out if an algebraic type is enumerated through Data.Generics?

Edward Kmett-2
On Tue, May 6, 2008 at 12:34 PM, Alfonso Acosta
<[hidden email]> wrote:

| So, the question is. Is there a way to figure out the arity of data
| constructors using Data.Generics ?

| I'm totally new to generics, but (tell me if I'm wrong) it seems that
| Constr doesn't hold any information about the data-constructor
| arguments. Why is it so?


Hmrmm,

Playing around with it, I was able to abuse gunfold and the reader
comonad to answer the problem :

fst $ (gunfold (\(i,_) -> (i+1,undefined)) (\r -> (0,r)) (toConstr
"Hello") :: (Int,String))

returns 2, the arity of (:), the outermost constructor in "Hello"

A longer version which does not depend on undefined would be to take
and define a functor that discarded its contents like:

> module Args where

> import Data.Generics

> newtype Args a = Args { runArgs :: Int } deriving (Read,Show)

> tick :: Args (b -> r) -> Args r
> tick (Args i) = Args (i + 1)

> tock = const (Args 0)

> argsInCons = runArgs $ (gunfold tick tock (toConstr "Hello") :: (Args String)

Basically all I do is rely on the fact that gunfold takes the 'tick'
argument and calls it repeatedly for each argument after a 'tock' base
case.

The use of the reader comonad or functor is to give gunfold a
'functor-like' argument to meet its type signature.

-Edward Kmett
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Figuring out if an algebraic type is enumerated through Data.Generics?

Bugzilla from alfonso.acosta@gmail.com
Thanks a lot for your answer, it was exactly what I was looking for.

Just for the record, based on your solution I can now easily code a
function to check if a Data value belongs to an enumerated algebraic
type (as I defined it in my first mail).

{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}

import Data.Generics

newtype Arity a = Arity Int
 deriving (Show, Eq)

consArity :: Data a => Constr -> Arity a
consArity = gunfold  (\(Arity n) -> Arity (n+1)) (\_ -> Arity 0)

belongs2EnumAlg :: forall a . Data a => a -> Bool
belongs2EnumAlg a = case (dataTypeRep.dataTypeOf) a of
  AlgRep cons -> all (\c -> consArity c == ((Arity 0) :: Arity a )) cons
  _ -> False

--  tests
data Colors = Blue | Green | Red
 deriving (Data, Typeable)

test1 = belongs2EnumAlg 'a' -- False
test2 = belongs2EnumAlg Red -- True
test3 = belongs2EnumAlg "a" -- False

On Tue, May 6, 2008 at 7:42 PM, Edward Kmett <[hidden email]> wrote:

>
> On Tue, May 6, 2008 at 12:34 PM, Alfonso Acosta
>  <[hidden email]> wrote:
>
>  | So, the question is. Is there a way to figure out the arity of data
>  | constructors using Data.Generics ?
>
>  | I'm totally new to generics, but (tell me if I'm wrong) it seems that
>  | Constr doesn't hold any information about the data-constructor
>  | arguments. Why is it so?
>
>
>  Hmrmm,
>
>  Playing around with it, I was able to abuse gunfold and the reader
>  comonad to answer the problem :
>
>  fst $ (gunfold (\(i,_) -> (i+1,undefined)) (\r -> (0,r)) (toConstr
>  "Hello") :: (Int,String))
>
>  returns 2, the arity of (:), the outermost constructor in "Hello"
>
>  A longer version which does not depend on undefined would be to take
>  and define a functor that discarded its contents like:
>
>  > module Args where
>
>  > import Data.Generics
>
>  > newtype Args a = Args { runArgs :: Int } deriving (Read,Show)
>
>  > tick :: Args (b -> r) -> Args r
>  > tick (Args i) = Args (i + 1)
>
>  > tock = const (Args 0)
>
>  > argsInCons = runArgs $ (gunfold tick tock (toConstr "Hello") :: (Args String)
>
>  Basically all I do is rely on the fact that gunfold takes the 'tick'
>  argument and calls it repeatedly for each argument after a 'tock' base
>  case.
>
>  The use of the reader comonad or functor is to give gunfold a
>  'functor-like' argument to meet its type signature.
>
>  -Edward Kmett
>  _______________________________________________
>  Haskell-Cafe mailing list
>  [hidden email]
>  http://www.haskell.org/mailman/listinfo/haskell-cafe
>
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Figuring out if an algebraic type is enumerated through Data.Generics?

Jules Bean
In reply to this post by Bugzilla from alfonso.acosta@gmail.com
Alfonso Acosta wrote:
> It would certainly be difficult map any Haskell type to VHDL, so, by
> now we would be content to map enumerate algebraic types (i.e.
>  algebraic types whose all data constructors have arity zero, e.g.
> data Colors = Green | Blue | Red)

Wouldn't it be much simpler to use the standard deriveable classes
Bounded and Enum, instead of an admittedly very clever trick using Data?

Metaprogramming comes in many shapes and sizes, and even the humble
deriving (Show,Enum,Bounded,Ord,Eq) gives you quite some leverage..

Jules
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Figuring out if an algebraic type is enumerated through Data.Generics?

Bugzilla from alfonso.acosta@gmail.com
On Wed, May 7, 2008 at 7:47 AM, Jules Bean <[hidden email]> wrote:

> Alfonso Acosta wrote:
>
> > It would certainly be difficult map any Haskell type to VHDL, so, by
> > now we would be content to map enumerate algebraic types (i.e.
> >  algebraic types whose all data constructors have arity zero, e.g.
> > data Colors = Green | Blue | Red)
> >
>
>  Wouldn't it be much simpler to use the standard deriveable classes Bounded
> and Enum, instead of an admittedly very clever trick using Data?

No, for the reasons explained in the probably_unnnecesary_background I
don't see how those instantiations would help.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe