elm-export
elm-export copied to clipboard
Support for algebraic sum types
I raised this issue a couple days ago with @mattjbray on his servant-elm package, and he directed me here, since servant-elm uses a fork of elm-export under the hood.
Basically, I'd love to see support for algebraic sum types in elm-export. I'd like to be able to get an ElmType
instance for something like data Position = Beginning | Middle | End deriving (Eq, Generic)
As an aside, your presentation on Elm at Red Badger was what convinced me to give Elm a go, so thanks for that!
I've had a quick look at this. For your example Position
type, generating type source (with toElmTypeSource
) basically works already. (I've just pushed a whitespace change & a unit test, but that's it.)
There are two problems though, and they both crop up if we give Middle
a parameter:
data Position = Beginning | Middle Int | End
The first problem is the Elm type source isn't generated correctly in this case. Shouldn't be hard to fix, but it needs doing.
The second, and more thorny, is the encoding/decoding issue it reveals. Take a look at this code:
import Data.Aeson
data Position
= Beginning
| Middle
| Ending
deriving (Generic,ElmType,ToJSON)
v1 = encode $ fromList [("pos" :: Text,Beginning)]
data Place
= Start
| Inside Int
| Stop
deriving (Generic,ElmType,ToJSON)
v2 = encode $ fromList [("pos" :: Text,Start)]
These types are basically identical, except one of them has a constructor with a parameter. I would have expected these two things to encode the same basic thing, but they don't:
λ> v1
"{\"pos\":\"Beginning\"}"
λ> v2
"{\"pos\":{\"tag\":\"Start\",\"contents\":[]}}"
Aeson encodes them differently, even though neither of these constructors has a parameter. That's...a pain. That's going to need some work.
So, in short, yes, I'd like this feature too. A little of it works, but it needs some design thought to get the rest working.
(Glad you like the presentation by the way. Come along to one of our Elm meetups and say hi! http://www.meetup.com/Elm-London-Meetup/)
Ok, thanks for taking a look at this, and for your prompt response. I'll try to take a deeper look at this myself.
Ref: https://github.com/bos/aeson/issues/267
After a design discussion with @mattjbray, we now have a plan for how to handle this cleanly. I'm going to need it myself very soon, so hopefully I'll get time to implement it...next week?
@krisajenkins did you end up working on this? I might take a stab at it if not.
I've started work on this in a fork. So far I've got encoding. I've aimed for compatibility with Aeson, which is somewhat annoying because of the stuff mentioned above (and more of it).
Here are the PositionEncoder and TimingEncoder test cases.
Some notes:
-
(Json.Encode.float) y0
has parentheses. It's kind of ugly, but they're necessary in some cases, particularly for more complicated types than float. - I haven't tested the actual Elm code nor its compatibility with aeson yet.
- The different ways there are to encode different kinds of sum types complicate the code. I'm not super happy with how I've dealt with this complexity thus far. Input is welcome.
- The decoder is the next step