Records in Haskell

Greg Weber greg at gregweber.info
Thu Sep 15 17:02:00 CEST 2011


Chris, Thank you for the real word experience report. I had assumed (because
everyone else told me) that importing qualified would be much, much better
than prefixing. I had thought that in your case since you are big on model
separation that you would have liked having a separate file for each model
to separate out all your model related code with. As a counter point, in all
of my (MVC) web application projects, we do have a separate file for each
model, and we like this approach. Each file usually contains a lot of
"business logic" related to the model- the only relatively empty model files
are ones that really represent embedded data. When I use MongoDB (which
actually supports embedded data instead of forcing you to create a separate
table), I will actually place the embedded models in the same file as the
model which includes them.

After my blog post complaining about records, I had a few people telling me
that I can just use existing polymorphism to avoid the name-spacing issue. I
collected the approaches here: http://www.yesodweb.com/wiki/record-hacks
I didn't think any of those telling me what i should do had actually tried
to do this themselves, particularly at any kind of larger scale. I am
interested to see if anyone has experience trying this approach, or if you
have considered it.

On Thu, Sep 15, 2011 at 3:00 AM, Christopher Done
<chrisdone at googlemail.com>wrote:

> I added my evaluation of the module-based approach to existing
> records, but on second thoughts it's maybe inappropriate, so I'll post
> it here. I saw that some people commented on the reddit discussion
> that the solution is to put your types in separate modules but it
> doesn't seem that anyone has tried to do this on a large scale. I
> tried it (and some other record paradigms including Has), but I don't
> think it scales. Here's why…
>
> Suppose I have 112 hand-crafted data types in my
> project (e.g. see attachment 51369.txt[1]), this creates a lot of
> conflicts in field names and constructor names. For example:
>
> {{{
> data Comment = Comment {
>      commentId           :: CommentId
>    , commentContent      :: Content
>    , commentReviewId     :: ReviewId
>    , commentSubmissionId :: SubmissionId
>    , commentConferenceId :: ConferenceId
>    , commentDate         :: ISODate
>    , commentReviewerNumber :: Int
>  } deriving (Show)
> }}}
>
> This is a real type in my project. It has fields like “id”, “content”,
> “reviewId”, “submissionId”, “date”. There are seven other data types
> that have a field name “submissionId”. There are 15 with
> “conferenceId”. There are 7 with “content”. And so on. This is just to
> demonstrate that field clashes ''do'' occur ''a lot'' in a nontrivial
> project.
>
> It also demonstrates that if you propose to put each of these 112 types
> into a separate module, you are having a laugh. I tried this around
> the 20 type mark and it was, apart from being very slow at compiling,
> ''very'' tedious to work with. Creating and editing these modules was a
> distracting and pointless chore.
>
> It ''also'' demonstrated, to me, that qualified imports are horrible
> when used on a large scale. It happened all the time, that'd I'd
> import, say, 10 different data types all qualified.  Typing map
> (Foo.id . BarMu.thisField) and foo Bar.Zot{x=1,y=2} becomes tedious
> and distracting, especially having to add every type module when I
> want to use a type. And when records use other types in other modules,
> you have ''a lot'' of redundancy. With the prefixing paradigm I'd write
> fooId and barMuThisField, which is about as tedious but there is at
> least less . confusion and no need to make a load of modules and
> import lines. Perhaps local modules would solve half of this
> problem. Still have to write “Bar.mu bar” rather than “mu bar”, but
> it'd be an improvement.
>
> I also have 21 Enum types which often conflict. I end up having to
> include the name of the type in the constructor, or rewording it
> awkwardly. I guess I should put these all in separate modules and
> import qualified,
> too. Tedious, though. At least in this case languages like C# and
> Java also require that you type EnumName.EnumValue, so c‘est la vie.
>
> [1]: http://hackage.haskell.org/trac/ghc/attachment/wiki/Records/51369.txt
>
> _______________________________________________
> Glasgow-haskell-users mailing list
> Glasgow-haskell-users at haskell.org
> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/glasgow-haskell-users/attachments/20110915/e4285b94/attachment-0001.htm>


More information about the Glasgow-haskell-users mailing list