haskell-to-elm / haskell-to-elm

Generate Elm types, encoders, and decoders from Haskell types
BSD 3-Clause "New" or "Revised" License
61 stars 8 forks source link

Elm instances for common Haskell types #16

Open seagreen opened 3 years ago

seagreen commented 3 years ago

I see this got discussed some here: https://github.com/folq/haskell-to-elm/pull/4, but that discussion was more about the specific instances involved: Map, Set, etc.

I'm curious about the big picture: can we think of a general rule to describe which Elm instances we want to provide, and which we don't?

Examining the extremes of the question may help: e.g. we definitely want (and do have) an instance for Int. We definitely don't want an instance for Graphics.Gloss.Data.Picture.Picture. Somewhere between those two is the boundary line, but where?

A couple possibilities:

  1. Aim for everything in base.

  2. Aim for everything in base, plus the idiomatic stdlib which is something like containers, unordered-containers, directory, etc

  3. Aim for everything in aeson.

What do you think?

Also: we have the option to break some of these out into a separate package from haskell-to-elm, something like haskell-to-elm-instances or at the extreme end we could use the https://github.com/NorfairKing/validity strategy. That way if we made a mistake or two users wouldn't be stuck with them.

ollef commented 3 years ago

I think 2 or 3 are probably what we should strive for (what's the difference?) to strike a balance between usefulness and not having too many exotic dependencies. But whatever we go for we need to add that

  1. The Elm type that the Haskell type maps to is the de facto standard, and
  2. The value mapping should preferably be one to one or at least be one to one for commonly used values (to justify mapping Int to Int and Maybe to Maybe).

It's a good point that we can create packages, at least for exotic or controversial instances. Perhaps that's what we should do for maps and sets?

seagreen commented 3 years ago

2 or 3 are probably what we should strive for (what's the difference?)

aeson probably includes a slightly bigger set of packages, but I think practically these are about the same.

  1. The Elm type that the Haskell type maps to is the de facto standard, and

Definitely agreed.

  1. The value mapping should preferably be one to one or at least be one to one for commonly used values (to justify mapping Int to Int and Maybe to Maybe).

Would you be willing to explain this for me? Without this would we not be able to map Int to Int?

It's a good point that we can create packages, at least for exotic or controversial instances. Perhaps that's what we should do for maps and sets?

I think this is a fantastic idea for the types like maps where there are multiple ways to do the mapping. Do you think we should create a package for maps and sets? This might be a good case for a multi-package-repo if you wanted to keep it here, if not we can make a new repo for it.

ollef commented 3 years ago

Would you be willing to explain this for me? Without this would we not be able to map Int to Int?

Haskell Ints are guaranteed to have at least the range [-2^29 .. 2^29-1] but e.g. on my machine they're 64-bit integers which don't map cleanly onto Elm's (i.e. Javascript's) doubles.

So the guaranteed range does map cleanly to Elm's type, but additional precision that a Haskell implementation provides might not.

The rationale for still mapping Ints to Ints is then basically that you shouldn't use Haskell Int if you're outside of the guaranteed range, and I would hope that the common usage is to not do that.

seagreen commented 3 years ago

I see now, thanks. I think that's a wise place to draw the line.