Discussion:
[Haskell-cafe] Get number of fields for non-record ADTs using Data type class?
Markus Läll
2018-10-29 18:56:02 UTC
Permalink
Dear list,

Is it possible te get the number of fields for data constructors for a
plain ADT, i.e something with no record fields? E.g for

data T = A Int Double | B String (Maybe String)

it would give 2 for both `A` and `B`.

For a record it's possible using the `constrFields` function from Data.Data.

I was trying to follow this tutorial by Christopher Done
https://chrisdone.com/posts/data-typeable, and I feel that it must be
possible somehow to get these numbers with the gmap*/gfold* functions, but
the use of them is over my head at the moment.


Best,
--
Markus LÀll
Li-yao Xia
2018-10-29 20:34:41 UTC
Permalink
This maps every field to 1, and folds them together using (+):

Data.Data.gmapQl (+) 0 (const 1) :: T -> Int

(There has to be a similarly easy solution using GHC.Generics instead
but I can't think of one...)

Li-yao
Post by Markus Läll
Dear list,
Is it possible te get the number of fields for data constructors for a
plain ADT, i.e something with no record fields? E.g for
data T = A Int Double | B String (Maybe String)
it would give 2 for both `A` and `B`.
For a record it's possible using the `constrFields` function from Data.Data.
I was trying to follow this tutorial by Christopher Done
https://chrisdone.com/posts/data-typeable, and I feel that it must be
possible somehow to get these numbers with the gmap*/gfold* functions,
but the use of them is over my head at the moment.
Best,
--
Markus Läll
_______________________________________________
Haskell-Cafe mailing list
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Artem Pelenitsyn
2018-10-29 20:42:16 UTC
Permalink
I don't think there is a point in looking for GHC.Generics-based solution,
as Data.Data is the exact match for this kind of problem.
--
Best, Artem
Post by Li-yao Xia
Data.Data.gmapQl (+) 0 (const 1) :: T -> Int
(There has to be a similarly easy solution using GHC.Generics instead
but I can't think of one...)
Li-yao
Post by Markus Läll
Dear list,
Is it possible te get the number of fields for data constructors for a
plain ADT, i.e something with no record fields? E.g for
data T = A Int Double | B String (Maybe String)
it would give 2 for both `A` and `B`.
For a record it's possible using the `constrFields` function from
Data.Data.
Post by Markus Läll
I was trying to follow this tutorial by Christopher Done
https://chrisdone.com/posts/data-typeable, and I feel that it must be
possible somehow to get these numbers with the gmap*/gfold* functions,
but the use of them is over my head at the moment.
Best,
--
Markus LÀll
_______________________________________________
Haskell-Cafe mailing list
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
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Li-yao Xia
2018-10-29 21:52:31 UTC
Permalink
Post by Artem Pelenitsyn
I don't think there is a point in looking for
GHC.Generics-based solution, as Data.Data is the exact match for this
kind of problem.
Although GHC.Generics has its shortcomings (usage complexity and compile
times), I still find it worthwhile to advocate as a statically-typed
alternative to the dynamically-typed Data.Data for many problems,
including this one.

Using the one-liner library (which is built around GHC.Generics), the
equivalent line of code is:

getSum . gfoldMap @AnyType (const 1) :: T -> Int

Data.Data is more visible mainly because it comes with a lot of
functionality baked into the standard library, whereas GHC.Generics
provides only a minimal interface and we have to find everything else in
separate packages. However, there is no fundamental reason why one is a
better fit than the other for the task of counting constructor fields.

Li-yao
Post by Artem Pelenitsyn
     Data.Data.gmapQl (+) 0 (const 1) :: T -> Int
(There has to be a similarly easy solution using GHC.Generics instead
but I can't think of one...)
Li-yao
Post by Markus Läll
Dear list,
Is it possible te get the number of fields for data constructors
for a
Post by Markus Läll
plain ADT, i.e something with no record fields? E.g for
data T = A Int Double | B String (Maybe String)
it would give 2 for both `A` and `B`.
For a record it's possible using the `constrFields` function from
Data.Data.
Post by Markus Läll
I was trying to follow this tutorial by Christopher Done
https://chrisdone.com/posts/data-typeable, and I feel that it
must be
Post by Markus Läll
possible somehow to get these numbers with the gmap*/gfold*
functions,
Post by Markus Läll
but the use of them is over my head at the moment.
Best,
--
Markus Läll
_______________________________________________
Haskell-Cafe mailing list
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
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Artem Pelenitsyn
2018-10-29 22:06:48 UTC
Permalink
Oh, didn't know about `one-liner`. This looks v. nice. Thank you!

-- Artem
Post by Li-yao Xia
Post by Artem Pelenitsyn
I don't think there is a point in looking for
GHC.Generics-based solution, as Data.Data is the exact match for this
kind of problem.
Although GHC.Generics has its shortcomings (usage complexity and compile
times), I still find it worthwhile to advocate as a statically-typed
alternative to the dynamically-typed Data.Data for many problems,
including this one.
Using the one-liner library (which is built around GHC.Generics), the
Data.Data is more visible mainly because it comes with a lot of
functionality baked into the standard library, whereas GHC.Generics
provides only a minimal interface and we have to find everything else in
separate packages. However, there is no fundamental reason why one is a
better fit than the other for the task of counting constructor fields.
Li-yao
Post by Artem Pelenitsyn
Data.Data.gmapQl (+) 0 (const 1) :: T -> Int
(There has to be a similarly easy solution using GHC.Generics instead
but I can't think of one...)
Li-yao
Post by Markus Läll
Dear list,
Is it possible te get the number of fields for data constructors
for a
Post by Markus Läll
plain ADT, i.e something with no record fields? E.g for
data T = A Int Double | B String (Maybe String)
it would give 2 for both `A` and `B`.
For a record it's possible using the `constrFields` function from
Data.Data.
Post by Markus Läll
I was trying to follow this tutorial by Christopher Done
https://chrisdone.com/posts/data-typeable, and I feel that it
must be
Post by Markus Läll
possible somehow to get these numbers with the gmap*/gfold*
functions,
Post by Markus Läll
but the use of them is over my head at the moment.
Best,
--
Markus LÀll
_______________________________________________
Haskell-Cafe mailing list
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
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Markus Läll
2018-11-03 17:06:59 UTC
Permalink
Hi and thank you for the answers -- I'll use Data for now since generics
seem scary at this point.

Another question :): is there a better way to get the constructor of some
partially applied data constructor. My current solution follows (and it
works), but I'm wondering if there is a better way? The issue is that I'm
feeding `undefined`s until the constructor is saturated and then get the
Constr, but it feels like using a loophole (the existence of `undefined`)
to achieve the result.

class GetConstr a where
getConstr :: a -> Constr
instance {-# OVERLAPPING #-} (GetConstr b) => GetConstr (a -> b) where
getConstr f = getConstr (f undefined)
instance {-# OVERLAPPABLE #-} (Data a) => GetConstr a where
getConstr a = toConstr a
Post by Artem Pelenitsyn
Oh, didn't know about `one-liner`. This looks v. nice. Thank you!
-- Artem
Post by Li-yao Xia
Post by Artem Pelenitsyn
I don't think there is a point in looking for
GHC.Generics-based solution, as Data.Data is the exact match for this
kind of problem.
Although GHC.Generics has its shortcomings (usage complexity and compile
times), I still find it worthwhile to advocate as a statically-typed
alternative to the dynamically-typed Data.Data for many problems,
including this one.
Using the one-liner library (which is built around GHC.Generics), the
Data.Data is more visible mainly because it comes with a lot of
functionality baked into the standard library, whereas GHC.Generics
provides only a minimal interface and we have to find everything else in
separate packages. However, there is no fundamental reason why one is a
better fit than the other for the task of counting constructor fields.
Li-yao
Post by Artem Pelenitsyn
Data.Data.gmapQl (+) 0 (const 1) :: T -> Int
(There has to be a similarly easy solution using GHC.Generics
instead
Post by Artem Pelenitsyn
but I can't think of one...)
Li-yao
Post by Markus Läll
Dear list,
Is it possible te get the number of fields for data constructors
for a
Post by Markus Läll
plain ADT, i.e something with no record fields? E.g for
data T = A Int Double | B String (Maybe String)
it would give 2 for both `A` and `B`.
For a record it's possible using the `constrFields` function from
Data.Data.
Post by Markus Läll
I was trying to follow this tutorial by Christopher Done
https://chrisdone.com/posts/data-typeable, and I feel that it
must be
Post by Markus Läll
possible somehow to get these numbers with the gmap*/gfold*
functions,
Post by Markus Läll
but the use of them is over my head at the moment.
Best,
--
Markus LÀll
_______________________________________________
Haskell-Cafe mailing list
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
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
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
--
Markus LÀll
Loading...