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

FromList instances for Attribute #25

Open
andrewthad opened this issue Nov 18, 2016 · 1 comment
Open

FromList instances for Attribute #25

andrewthad opened this issue Nov 18, 2016 · 1 comment

Comments

@andrewthad
Copy link
Contributor

andrewthad commented Nov 18, 2016

Lately, I've been writing more functions that take an Attribute collection as an argument. I'm trying to think of ways to make it easier to users (mostly myself) to call these functions. One strategy I've started adopting is accepting a Foldable collection of Attributes. Here's an example from a library of mine:

footer_ :: (Monad m, Foldable t) => t Attribute -> WidgetT site m a -> WidgetT site m a

I know that blaze has the ! operator, but I've always preferred concatenating all of my Attributes first and then applying them to the element. And that's exactly what this function does. It uses the Foldable instance just to call fold on the collection. The end user ends up writing:

footer [class_ "foo", id_ "bar"] "Stuff in the footer"

I was thinking though that it's annoying to have the Foldable constraint at all. It could be written to take a list of Attributes instead, but I still consider that an unneeded indirection. The function could alternatively be written as:

footer_ :: Monad m => Attribute -> WidgetT site m a -> WidgetT site m a

But then the user must call fold (or mconcat) manually:

footer (fold [class_ "foo", id_ "bar"]) "Stuff in the footer"

Which I don't want to have to do when writing code. All of this is the background for why I would like a FromList instance. The instance I'm describing could technically exist for any Monoid. It is written as:

class IsList Attribute where
  type Item Attribute = Attribute
  fromList = fold
  toList x = [x]

The neat thing about this is that it would enable me to define footer_ to accept an Attribute, and in the common use case (a list of attributes of known at compile time), the user doesn't have to call fold manually:

footer_ :: Monad m => Attribute -> WidgetT site m a -> WidgetT site m a
footer_ = ...

>>> footer_ [class_ "bar", id_ "baz"] "Content"

The bad thing is that this instance does not satisfy the law fromList . toList = id. However, given that users cannot inspect Attributes to discover their structure, I would argue that the law is satisfied "up to interpretation", similar to how certain monads only satisfy the monad laws under an interpretation function. Anyway, let me know what you think. Having this instance would be helpful for a lot of the stuff I'm working on.

@andrewthad
Copy link
Contributor Author

Any thoughts on this?

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

1 participant