krisajenkins / elm-export Goto Github PK
View Code? Open in Web Editor NEWCreate Elm types and JSON decoders from Haskell source.
License: Eclipse Public License 1.0
Create Elm types and JSON decoders from Haskell source.
License: Eclipse Public License 1.0
Hi, is there anyone working on upgrading elm-export to Elm 0.19? If so what is the status, and can I help? :)
I find I'm hacking a lot of stuff into a local elm-export repo and building that in parallel with my project. Going forward, it seems likely that people may have conflicting ideas about how to map Haskell types to Elm types and back (e.g. for dates, container types) and may want to add Haskell types from other obscure libraries for a particular project. You can't do this now because none of the internals are available.
Perhaps an Elm.Internal
module could be added with the usual caveats about changes, so that users can add these customizations to their own projects if they wish.
Given the Haskell data type
data Foo = Foo { foo :: Map String Int }
An example response from Aeson (via Servant) is
{
"foo": {
"1": 1,
"2": 2
}
}
However, the decoder for Foo
generated by elm-export
is the following:
decodeFoo : Decoder Foo
decodeFoo =
decode Foo
|> required "foo" (map Dict.fromList (list (map2 (,) (index 0 string) (index 1 int))))
i.e. it's expecting a list, not an object. This mismatch can be verified by actually attempting to decode data from Elm:
"Expecting a List at _.foo but instead got: {\"1\":1,\"2\":2}"
I have created a repository with a self-contained program that can be used to reproduce the issue here: https://github.com/ehamberg/elm-export-test
I have tested this on version 0.6.0.1 and devel@ 7ca89b88393925ebd27ace8c919cec1fe0f511c0
.
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
import Data.Proxy
import Elm
import GHC.Generics
data Foo = Foo { getIt :: String} deriving (Generic, ElmType)
main :: IO ()
main = print $ toElmTypeRef (Proxy :: Proxy (String, Foo))
Prints "( String, type alias Foo =\n { getIt : String\n } )"
while it worked correctly with 0.5.0.2, I wonder what commit is used for 0.6.0.0?
Let's try ansi-wl-pprint
and see if it makes the pretty-printing less of a hit & miss affair. :-D
Are parametrized types supported? E.g. How would I turn a Haskell type
data Tree a = Leaf a | Node (Tree a) (Tree a)
deriving (Generic, ElmType)
into an Elm declaration
type Tree a = Leaf a | Node (Tree a) (Tree a)
?
Spec ["Generated", "API"]
should mean Generated folder is created, but it will not be.
Hi, I don't know much about Elm yet, but I put something together that hit an non-exhaustive pattern match panic - there's no MultipleConstructors
pattern for render
ing an ElmConstructor
.
Does this have to do with #6?
I think the JSON encoder for Date
is not compatible with Aeson. It uses the toString
method which produces
(elm repl)
> toString (Date.fromTime 1491938767000)
"<Tue Apr 11 2017 12:26:07 GMT-0700 (PDT)>" : String
but aeson is expecting an ISO8601 date
https://hackage.haskell.org/package/aeson-1.1.1.0/src/Data/Aeson/Parser/Time.hs#day
(ghci)
Prelude> :set -XOverloadedStrings
Prelude> import Data.Time.Calendar as D
Prelude D> import Data.Aeson as A
Prelude D A> fmap D.toGregorian (A.decode "\"2017-01-01\"")
Just (2017,1,1)
I'm happy to submit a pull request.
@krisajenkins: I'd like to encourage you to release this to hackage in it's current state. It would make it slightly easier to use and -- more importantly -- more discoverable. Hackage makes no promises regarding stability or maturity. (You could add stability: alpha
to the cabal file to make the status of the project more explicit.)
In short, these are incompatible:
toElmTypeSourceWith (defaultOptions {fieldLabelModifier = withPrefix "post"}
toElmEncoderSourceWith (defaultOptions {fieldLabelModifier = withPrefix "post"}
Simple workaround I have used is:
--- a/src/Elm/Encoder.hs
+++ b/src/Elm/Encoder.hs
@@ -44,7 +44,7 @@ instance HasEncoder ElmValue where
valueBody <- render value
return . spaceparens $
dquotes (stext (fieldModifier name)) <> comma <+>
- (valueBody <+> "x." <> stext name)
+ (valueBody <+> "x." <> stext (fieldModifier name))
render (ElmPrimitiveRef primitive) = renderRef primitive
render (ElmRef name) = pure $ "encode" <> stext name
render (Values x y) = do
But then this changes semantics and in't compatible with existing encoders.
newtype Email = Email Text deriving (Eq, Show, Read, Generic)
deriving instance ElmType Email
-- [snip]
specs :: [Spec]
specs =
[
Spec ["AutoGenerated", "Api"]
( defElmImports
: toElmTypeSource (Proxy :: Proxy Types.Email)
: toElmDecoderSource (Proxy :: Proxy Types.Email)
: toElmEncoderSource (Proxy :: Proxy Types.Email)
)
]
Error:
Prelude Elm CodeGen> specsToDir specs "/tmp/elm"
Writing: /tmp/elm/AutoGenerated/Api.elm
*** Exception: src/Elm/Encoder.hs:(37,3)-(39,67): Non-exhaustive patterns in function render
Right now the API generator only supports JSON
When trying out the Person
example in the readme, I stumbled upon some errors thrown by the generated code. Symbols like required
were not found. When I checked out the documentation of the core library, I was surprised to find that required
was never a thing in Json.Decode
.
After a while I figured out that it's a function from a separate library: elm-decode-pipeline
. The example also imports Json.Decode.Extra
, which is from the package elm-json-extra
.
It's probably a good idea to document these dependencies, as it would make it easier to get a working prototype.
Edit: This also means the example contains an error, as it doesn't import Json.Decode.Pipeline
.
Maybe it could be added to your Exts.Json.Decode
module?
Todo:
We're on stackage now. It's the big time. But, this is like the saddest page on the internet: https://www.stackage.org/haddock/nightly-2017-02-02/elm-export-0.6.0.0/Elm.html
Hello, first I would like to say thanks for this awesome module. It was very easy to get going for the most basic case where the JSON field names match record names, and all fields are required.
I quickly ran into issues where I had types with slightly more complex serializers/deserializers. For example, both Aeson and Elm allow for optional JSON fields given a default value:
data Person = Person
{ noteid :: String
, name :: String
, birth :: String
, gender :: String
}
instance FromJSON Person where
parseJSON = withObject "person" $ \o -> do
id <- o .: "id"
name <- o .:? "name" .!= "unknown"
birth <- o .:? "birth" .!= "unknown"
gender <- o .:? "gender" .!= "unknown"
return Person{..}
decodePerson : Decoder Person
decodePerson =
decode Person
|> required "id" string
|> optional "name" string "unknown"
|> optional "birth" string "unknown"
|> optional "gender" string "unknown"
It seems to me that it should be possible to create custom instances for more complex cases as you can do in Aeson. I can work around this by writing the Elm decoder by hand (in Elm), but I think that there is value in having all of my types and deserializers/serializers defined in the same place, and compiled in the same step. What are your thoughts?
@kosmikus gave very good talk at ZuriHac 2016 about it: https://www.youtube.com/watch?v=sQxH349HOik
I personally also use it to write generic code, and after you get familiar with the combinators (i.e. don't recurse yourself) code might start seeing magical. For example I generate swagger schema type (i.e. the very related problem this package solves), only for record-like types though: https://github.com/futurice/haskell-futurice-prelude/blob/9c4c13e6da9142e4a4b246ef3b8b189fbc4e160f/src/Futurice/Generics.hs#L216-L248
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!
Elm 0.18 (will be released today) won't support primes in names anymore.
We should make sure to respect that.
https://github.com/elm-lang/elm-platform/blob/master/upgrade-docs/0.18.md#no-more-primes
I was getting a runtime (!) exception with the following;
myApp: src/Elm/Record.hs:(12,1)-(67,23): Non-exhaustive patterns in function render
Pulling down the elm-export
source and building;
$ stack build --pedantic
elm-export/src/Elm/Encoder.hs:13:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘render’:
Patterns not matched:
(TopLevel (TopLevel _))
(TopLevel (Record _ _))
(TopLevel (Constructor _ _))
(TopLevel (Selector _ _))
...
elm-export/src/Elm/Record.hs:12:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘render’:
Patterns not matched:
(TopLevel (TopLevel _))
(TopLevel (DataType _ (TopLevel _)))
(TopLevel (DataType _ (DataType _ _)))
(TopLevel (DataType _ (Constructor _ _)))
...
I tried fixing it but couldn't quite grok things.
Adding render _ = return ""
to both Encoder and Record files "did the trick" in terms of the runtime exception in my dependant app, but I doubt that's the Right™ fix.
Would be happy to submit a PR with some direction 😄
Hey,
I’ve hacking and contributing around on https://github.com/FPtje/elm-export. I think it’d be a good thing to merge its master
into yours. If you don’t feel you want to maintain the project anymore, maybe it’d be a good thing to add a few more contributors so that the project can still live on?
A few things I added lately:
NonEmpty
and Natural
support.UTCTime
get their encoders / decoders Em part.There is no pattern corresponding to MultipleConstructors
in the render
function in the HasDecoder
instance of ElmConstructor
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.