Managing a sum type with a lot of constructors

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

Managing a sum type with a lot of constructors

Adam Flott
I have a sum type with a lot of constructors and I'm not sure how to represent
the type with maintainability in mind. For example,

    data A = A1
           | A2 Int
           | A3 Text Int32 Bool
           | ...
           | A100 Bool

Every inner type is concrete. There are 100+ constructors with no sign of ever
getting reduced.

What technique would you recommend to keep the sum type approach but not having
to define them all in one spot? I'm thinking 1 inner type + 1 function to
construct per file (if that's possible).
_______________________________________________
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: Managing a sum type with a lot of constructors

Michael Burge
If you have that many constructors, you probably aren't pattern-matching against the whole thing everywhere. So you could extract the few functions that use the entire type for case analysis into a typeclass, make each constructor its own type, and implement the typeclass:

Instead of:

something :: A -> IO ()
something A1 = putStrLn "hello"
something (A2 _) = putStrLn "world"

Use:

data A1
data A2 = A2 Int

class RelatedConst a of
  something :: a -> IO ()

instance RelatedConst A1 where
  something _ = putStrLn "hello"

instance RelatedConst A2 where
  something _ = putStrLn "world"

Then, each declaration and instance could go in its own file.

If on the other hand, you are using lots of partial case matches everywhere, see if there are commonalities and extract a typeclass for each group


On Wed, Aug 23, 2017 at 6:29 PM, Adam Flott <[hidden email]> wrote:
I have a sum type with a lot of constructors and I'm not sure how to represent
the type with maintainability in mind. For example,

    data A = A1
           | A2 Int
           | A3 Text Int32 Bool
           | ...
           | A100 Bool

Every inner type is concrete. There are 100+ constructors with no sign of ever
getting reduced.

What technique would you recommend to keep the sum type approach but not having
to define them all in one spot? I'm thinking 1 inner type + 1 function to
construct per file (if that's possible).
_______________________________________________
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: Managing a sum type with a lot of constructors

David Turner-2
In reply to this post by Adam Flott
Hi,

We have a sum type of 151 constructors (and growing) in one project. There is a somewhat natural grouping of the constructors into 24 groups (with between 1 and 32 constructors in each group) so we used that to break it down into the two levels:

data Group1 = Ctor1 Int | Ctor2 Bool | ...
data Group2 = Ctor5 String | Ctor6 Double | ...
...
data A = Group1 Group1 | Group2 Group2 | ...

This wasn't enough, so then we cheated and wrote some code-gen. The datatype is described as data (think YAML or JSON) and then there's a short program which generates the declarations, including Haddock comments, and various useful functions such as somewhat-custom JSON serialisation. Each group gets its own module, which gives faster recompilation on changes. We could have used TemplateHaskell, except we wouldn't have got such nice Haddock docs (and, ew, TemplateHaskell) and it would all have had to have been in one module.

Hope that helps,

David



On 24 August 2017 at 02:29, Adam Flott <[hidden email]> wrote:
I have a sum type with a lot of constructors and I'm not sure how to represent
the type with maintainability in mind. For example,

    data A = A1
           | A2 Int
           | A3 Text Int32 Bool
           | ...
           | A100 Bool

Every inner type is concrete. There are 100+ constructors with no sign of ever
getting reduced.

What technique would you recommend to keep the sum type approach but not having
to define them all in one spot? I'm thinking 1 inner type + 1 function to
construct per file (if that's possible).
_______________________________________________
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: Managing a sum type with a lot of constructors

Adam Flott
In reply to this post by Michael Burge
My input I'm parsing into a data structure is URL query string like
<key>=<value> and separated by a delimiter. Ultimately what I want back is of
type `Data.Set.Set Text (v :: *)`. However I don't know how to represent that
and don't want to build an HList like interface for it.


On Wed, 23 Aug 2017 18:45:13 -0700
Michael Burge <[hidden email]> wrote:

> If you have that many constructors, you probably aren't pattern-matching
> against the whole thing everywhere. So you could extract the few functions
> that use the entire type for case analysis into a typeclass, make each
> constructor its own type, and implement the typeclass:
>
> Instead of:
>
> something :: A -> IO ()
> something A1 = putStrLn "hello"
> something (A2 _) = putStrLn "world"
>
> Use:
>
> data A1
> data A2 = A2 Int
>
> class RelatedConst a of
>   something :: a -> IO ()
>
> instance RelatedConst A1 where
>   something _ = putStrLn "hello"
>
> instance RelatedConst A2 where
>   something _ = putStrLn "world"
>
> Then, each declaration and instance could go in its own file.
>
> If on the other hand, you are using lots of partial case matches
> everywhere, see if there are commonalities and extract a typeclass for each
> group
>
>
> On Wed, Aug 23, 2017 at 6:29 PM, Adam Flott <[hidden email]> wrote:
>
> > I have a sum type with a lot of constructors and I'm not sure how to
> > represent
> > the type with maintainability in mind. For example,
> >
> >     data A = A1
> >            | A2 Int
> >            | A3 Text Int32 Bool
> >            | ...
> >            | A100 Bool
> >
> > Every inner type is concrete. There are 100+ constructors with no sign of
> > ever
> > getting reduced.
> >
> > What technique would you recommend to keep the sum type approach but not
> > having
> > to define them all in one spot? I'm thinking 1 inner type + 1 function to
> > construct per file (if that's possible).
> > _______________________________________________
> > 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.