Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More information about parameterised type constructors #4

Open
buggymcbugfix opened this issue Sep 11, 2018 · 3 comments
Open

More information about parameterised type constructors #4

buggymcbugfix opened this issue Sep 11, 2018 · 3 comments

Comments

@buggymcbugfix
Copy link

This library looks super interesting. The README states that barbies are a common Haskell idiom.

What is the usual name for this and where can I find out more?

Also, where can I find example uses?

@jcpetruzza
Copy link
Owner

Hey, good questions!

What is the usual name for this and where can I find out more?

I don't know if they have a standard name. I used to refer to them as "types parametrized by a functor", but I find it too long. The parameterized-utils package defines analogs of the FunctorB / TraversableB classes (but without the automatic derivation of instances); and there they call them "structures that accept a single parametric type parameter", which is probably worse 😃

I'm sure the idea of putting a type-parameter f in front of your concrete types in a record goes back a long time. I seem to remember I first read someone mentioning it in the haskell-cafe mailing list many years ago, but I'm now unable to find it. It is a sort of folk-knowledge, I think, and I've seen data types defined in that way in the past in the wild, but unfortunately I don't know of any place to go read about it.

Also, where can I find example uses?

I gave a talk about the library at one one of the haskell meetups in London some time ago. The video is not up yet, I think, but the slides were for the most part code. Let me know if you need help reconstructing the context.

I'm using this mostly at work and I don't currently have other code examples in public repos, but these are some scenarios were I found it useful:

  • Working with data that needs to be read from outside (from a db, an http request) and "validated" before you can process it. Specially so, if you want to be able to know, which fields are ok, and which ones are rejected (e.g., to report them to the user). For instance, you have some Form f representing a web-form, and you could have all these versions of the type:
  • A Form Identity is one with all the data validated,
  • a Form (Const Text) is a raw form where you've just collected the text input from the user,
  • a Form (Either ValidationError) is one where where you've parsed each individual field and contain either a value or an error message,
  • a Form Parser describes how to parse each individual field.

Using bzipWith you can write something with type Form Parser -> Form (Const Text) -> Form (Either ValidationError) to do the parsing. You can check if it is valid by using btraverse to get a Form (Either ValidationError) -> Maybe (Form Identity). This is conceptually the same example you will find in the slides, but in another setting.

  • Similarly, you may have two versions of a Form Identity, and you want to produce a "diff" that contains only the values that are different in the new version. Using bzipWith and btraverse you then get a function Form Identity -> Form Identity -> Maybe (Form Maybe), that returns Nothing if the two versions are equal, or Just diff in case there is at least one field where they differ.

  • You've stored these diffs in some sort of event log, which you can think of as a [Form Maybe]. You are given this log and want to reconstruct the final value of the form. So you use bmap to turn this into a [Form Last] and because you should be able to get a Monoid instance for Form Last, you can mconcat this list to get a Form Last which you can then turn into a Form Maybe or a Maybe (Form Identity), etc.

  • Of course, in real life, you probably have many types of different web-forms, so you should substitute the concrete Form type by a form type-variable in all the examples above! And if every type of form is to be saved on a database, you can use something like this to describe the mapping of each form with some primary key to a db:

data DbTable pk form = DbTable TableName (Column pk) (Form Column)
data Column a = Column ColumnName (ToDb a) (FromDb a)

And because a TraversableB can be folded, you can use a DbTable pk form to programmatically generate the inserts, updates, selects, etc. or even generate your full db schema.

Hope this makes some sense!

@buggymcbugfix
Copy link
Author

Thank you for this detailed reply! I think the context of the talk would be quite helpful, I presume I will have to pester Derek? If not, I will try to reconstruct, but what you have written here already makes a lot of sense and seems very sensible.

I will try to make use of Barbies in my code and see how I fare and what the caveats may be.

@mstksg
Copy link

mstksg commented Sep 30, 2018

@isovector explores these concepts pretty deeply in this blog post and calls them "higher-kinded data" :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants