Giter VIP home page Giter VIP logo

elm-bridge's Introduction

Elm Bridge

Build Status

Hackage Deps

Intro

Hackage: elm-bridge

Building the bridge from Haskell to Elm and back. Define types once, use on both sides and enjoy easy (de)serialisation. Cheers!

This version of the package only supports Elm 0.19. Version 0.5.2 supports Elm 0.18, and Version 0.3.0.2 supports Elm 0.16 and Elm 0.17.

Note that the bartavelle/json-helpers package, with version >= 1.2.0, is expected by the generated Elm modules.

Usage

{-# LANGUAGE TemplateHaskell #-}
import Elm.Derive
import Elm.Module

import Data.Proxy

data Foo
   = Foo
   { f_name :: String
   , f_blablub :: Int
   } deriving (Show, Eq)

deriveBoth defaultOptions ''Foo

main :: IO ()
main =
    putStrLn $ makeElmModule "Foo"
    [ DefineElm (Proxy :: Proxy Foo)
    ]

Output will be:

module Foo where

import Json.Decode
import Json.Decode exposing ((:=))
import Json.Encode
import Json.Helpers exposing (..)


type alias Foo  =
   { f_name: String
   , f_blablub: Int
   }

jsonDecFoo : Json.Decode.Decoder ( Foo )
jsonDecFoo =
   ("f_name" := Json.Decode.string) `Json.Decode.andThen` \pf_name ->
   ("f_blablub" := Json.Decode.int) `Json.Decode.andThen` \pf_blablub ->
   Json.Decode.succeed {f_name = pf_name, f_blablub = pf_blablub}

jsonEncFoo : Foo -> Value
jsonEncFoo  val =
   Json.Encode.object
   [ ("f_name", Json.Encode.string val.f_name)
   , ("f_blablub", Json.Encode.int val.f_blablub)
   ]

Also, there are functions Elm.Json.stringSerForSimpleAdt and Elm.Json.stringParserForSimpleAdt to generate functions for your non-JSON ADT types.

For more usage examples check the tests or the examples dir.

Install

Haskell

  • Using cabal: cabal install elm-bridge
  • From Source: git clone https://github.com/agrafix/elm-bridge.git && cd elm-bridge && cabal install

Elm

  • elm package install bartavelle/json-helpers

or, for Elm 0.19:

  • elm install bartavelle/json-helpers

Contribute

Pull requests are welcome! Please consider creating an issue beforehand, so we can discuss what you would like to do. Code should be written in a consistent style throughout the project. Avoid whitespace that is sensible to conflicts. (E.g. alignment of = signs in functions definitions) Note that by sending a pull request you agree that your contribution can be released under the BSD3 License as part of the elm-bridge package or related packages.

elm-bridge's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elm-bridge's Issues

Test suite compilation failure

[1 of 1] Compiling Main             ( test/EndToEnd.hs, dist/build/end-to-end-tests/end-to-end-tests-tmp/Main.o )

test/EndToEnd.hs:60:14:
    GHC stage restriction:
      ‘unwrapUnaryRecords’ is used in a top-level splice or annotation,
      and must be imported, not defined locally
    In the first argument of ‘deriveBoth’, namely
      ‘defaultOptions
         {allNullaryToStringTag = False, unwrapUnaryRecords = False}’
    In the expression:
      deriveBoth
        (defaultOptions
           {allNullaryToStringTag = False, unwrapUnaryRecords = False})
        ''Simple01

test/EndToEnd.hs:60:61:
    ‘unwrapUnaryRecords’ is not a (visible) constructor field name

ETypeDef instances for base types

Hi, I am looking at porting servant-elm to elm-bridge or creating a similar library that works with elm-bridge. The reason being is that I really like that elm-bridge generates types that are "aeson compatible" , and that elm-bridge is more flexible in types that it supports (ie. sum types).

However, one current stumbling block is that a servant JSON API can be created that returns any type with a FromJSON instance. Since aeson has built-in instances for most base types ([a], Either, Maybe, etc.) and a lot of common types (like Text), there's a lot of types that will work out of the box in servant responses that don't have ETypeDef instances.

Do you think it makes sense to include default instances for types that already have analogs in Elm? Or do you think there is a better approach to solving this problem? Thanks.

Update for Elm version 0.17

I have updated my pull request for updating to Elm version 0.17. The changes that I have made are:

Add a new module, Elm.Versions exporting a type
data ElmVersion
= Elm0p16
| Elm0p17

Modify Elm.Module, adding a function
MakeElmModuleWithVersion which takes an ElmVersion as it's first parameter, hence switching on version, and modified the existing makeElmModule to be makeElmModuleWithVersion Elm0p16, so that existing code should run without any changes.

Finally, I have added two tests to ModuleSpec, one to test makeElmModuleWithVersion for Elm0p16 and one for Elm0p17.

Please suggest any changes.

More readable output

Hello,

Is it possible to produce more readable output? It would be great to have these improvements:

  • no redundant brackets
  • space before colon in type definition
  • (=>) used in encoder instead of (,)
  • 'val' replaced by one letter variable like 'o'
  • import Json.Encode as E, Json.Decode as D and Json.Helpers as H
  • use (|:) from Json.Decode.Extra instead of 'andThen' and chained lambda

Preparing the elm-package

I published a formatted version of the elm package for testing, but I do not know why my code samples are truncated :(

I will keep on testing with a pair of real life projects until all of this is stable enough.

General questions about design of elm-bridge

I'm extending this library to auto-generate Elm API wrappers based on Servant type-signatures [1]. I've pretty much wrapped my head around the internals, but am scratching my head over the following:

  1. The philosophical / conceptual difference between ETypeDef and EType. It seems to me that EType is some sort of Elm-compatible subset of TH.Type, but I'm not so sure about ETypeDef.
  2. deriveElm uses TH to generate instances for IsElmDefinition. However, there are no IsElmDefinition instances for things like String or Bool. It this because you don't want to have "global" Haskell <=> Elm type-mappings forced upon users of this library, allowing them, instead, to make a choice on a case-by-case basis by using makeModuleContentWithAlterations infra?
  3. Even then, if as an end-user, I want to define an IsElmDefinition for my app, how would I do that for something like String / Bool? How does one write a sensible implementation for compileElmDef :: Proxy a -> ETypeDef? What value should this function return? The only possible option is ETypePrimAlias, but I'm not sure how that would work? (this should give you some context about why I'm asking the very first question).

[1] Btw, are you open to a PR for this functionality? I don't see the point in releasing yet another elm <=> haskell library.

Bridge, Lens and variables beginning with underscores

Currently, if you use this module to convert types on which you are using the Lens library, you get an invalid output file since it generates variables with underscores. Fixing this manually is possible, but increasingly tedious as the number of types increases.

Issue with UTCTime to Posix

It would appear that there are default alterations UTCTime that convert fields into Posix.
That's great, but it doesn't seem to be followed through in the generated code.

For example, it will correctly rename the field, but it does not import Time and uses a decoder called jsonDecPosix (autogenerated naming). That decoder does not exist.

Is there another way around this issue? Is there something I'm missing? We are using servant-elm but I tried directly through elm-bridge and got the same results.

This is an example (ignore the silly naming) from the generated code:

type alias FweetDto  =
   { fwuser: FwuserDto
   , fwody: String
   , fwimestamp: Posix
   }

jsonDecFweetDto : Json.Decode.Decoder ( FweetDto )
jsonDecFweetDto =
   Json.Decode.succeed (\pfwuser pfwody pfwimestamp -> {fwuser = pfwuser, fwody = pfwody, fwimestamp = pfwimestamp})
   |> required "fwuser" (jsonDecFwuserDto)
   |> required "fwody" (Json.Decode.string)
   |> required "fwimestamp" (jsonDecPosix)```

Base on smaller elm codegen library?

I've thrown together a library that just generates Elm types from Haskell ones:

https://github.com/mitchellwrosen/elm-codegen

Would you be interested in basing this library atop that one? If so, I can throw it up on Hackage and am willing to maintain it.

The main benefit here is separation of concerns (and maintenance) - after just extracting an Elm type from a Haskell one, there's more to do of course... how the Elm type should look (e.g. optionally turning records into type aliases or messing with record field names), pretty-printing, JSON encoder/decoder generation, etc.

Also, fwiw, my template haskell code does handle the "phantom type variable" case just fine, which I noticed is still an open ticket here.

How to deal with UTCTime?

What's the best way to deal with UTCTime? I tried deriving the Elm definition and here's what showed-up on the Elm side:

type alias UTCTime  =
   { utctDay: Day
   , utctDayTime: DiffTime
   }

jsonDecUTCTime : Json.Decode.Decoder ( UTCTime )
jsonDecUTCTime =
   ("utctDay" := jsonDecDay) >>= \putctDay ->
   ("utctDayTime" := jsonDecDiffTime) >>= \putctDayTime ->
   Json.Decode.succeed {utctDay = putctDay, utctDayTime = putctDayTime}

jsonEncUTCTime : UTCTime -> Value
jsonEncUTCTime  val =
   Json.Encode.object
   [ ("utctDay", jsonEncDay val.utctDay)
   , ("utctDayTime", jsonEncDiffTime val.utctDayTime)
   ]

Is this the idiomatic way of dealing with timestamps on the Elm side? (I'm new to Elm, so please pardon this newbie question). If not, then how does one specify some sort of "mapping" between an idiomatic Haskell type and its corresponding idiomatic Elm counterpart?

Are the tests actually running the generated elm code?

I think I may have found a bug in the json codecs being generated by elm-bridge and I wanted to confirm based on the tests. There's some property testing going on there, but I'm not sure if the following roundtrip test is being done for random combinations of Aeson.Options and various Haskell types:

Haskell => JSON => Elm => JSON => Haskell

Can anyone please confirm this for me?

Recursive types

Hi there - there's an issue creating Elm decoders for recursive types, apparently Elm cannot handle recursive values due to it's strictness.

jsonDecEdit is defined directly in terms of itself, causing an infinite loop.

Maybe the solution is to give it a dummy argument to a helper function? e.g.


jsonDecEdit_ : () -> Json.Decode.Decoder Edit
jsonDecEdit _ =  -- real decoder goes here

jsonDecEdit : Json.Decode.Decoder Edit
jsonDecEdit = jsonDecEdit_ ()
type Edit  =
    Add Int Object
    | Delete Int
    | Move (List Int) Vec2
    | Multi (List Edit)

jsonDecEdit : Json.Decode.Decoder ( Edit )
jsonDecEdit =
    let jsonDecDictEdit = Dict.fromList
            [ ("Add", Json.Decode.map2 Add (Json.Decode.index 0 (Json.Decode.int)) (Json.Decode.index 1 (jsonDecObject)))
            , ("Delete", Json.Decode.map Delete (Json.Decode.int))
            , ("Move", Json.Decode.map2 Move (Json.Decode.index 0 (Json.Decode.list (Json.Decode.int))) (Json.Decode.index 1 (jsonDecVec2)))
            , ("Multi", Json.Decode.map Multi (Json.Decode.list (jsonDecEdit)))
            ]
    in  decodeSumObjectWithSingleField  "Edit" jsonDecDictEdit

Higher Kinded Data

Thank you for the great work on this library. Indispensable in keeping my Haskell types in sync with the front end types in elm.

I'm am using this library via servant-elm. In the backend I use beam, where types are required to look like

data UserT f = User
  { id :: C f Int32
  , name :: C f Text
  }

and since type C Identity a = a then type User = UserT Identity is equivalent with

data User = User
  { id :: Int32
  , name :: Text
  }

I can derive FromJson, ToJson from the aeson library and ToSchema from the openapi3 library for both User types above. However I can't find a way to derive a sensible IsElmDefinition for the type alias version? It should not include the f parameter.
Is this possible, or what needs to be done to make this possible?
Right now my workaround is doubling every higher kinded type with a simple type that I can derive IsElmDefinition for, but that seems do defeat the purpose.

Support For Haskell Type Alias

type A = String 
data Foo = Foo 
  { a :: A
  }

produces

type alias Foo = 
  { a :: A
  }

Which gives the error that the type A isn't defined. Is there support for recursively deriving types?

Converting sum types

Hi,

I'm trying to convert my Haskell Either a b to an Elm Either a b but the encoder and decoder for this are… weird. It creates jsonDecEither and jsonEncEither decoders that need 2 arguments! I'd expect a set of encoder/decoder per constructor. Are sum types supported?

Nice job by the way, for all the rest it's been working like a charm!

Consider adding Tagged instance

Hi!,
we use a lot phantom types with Tagged, currently are derived like this:

data EmailT
type Email = Tagged EmailT Text
type alias User  =
   { name: String
   , email: Email
   }

jsonDecUser : Json.Decode.Decoder ( User )
jsonDecUser =
   ("name" := Json.Decode.string) >>= \pname ->
   ("email" := jsonDecEmail) >>= \pemail ->
   Json.Decode.succeed {name = pname, email = pemail}

Apply the `constructorTagModifier` to the JSON but not the type def?

I have an existing type like this in my Haskell app:

data FooType
  = FooTypeEnum { fooTypeValues :: [Text] }
  ...

With JSON serialization defined which outputs:

{"enum": { "values": ["value1", "value2", ...]}}

Which is achieved by using the fieldLabelModifier and constructorTagModifier options for Aeson.

I'm using the analogous option values in elm-bridge to get the json encoding/decoding to match up, but the issue is that constructorTagModifier applies to both the type definition AND the json encoders/decoders, where I want it to apply to only the latter.

So I end up with the correct json encoding/decoding, but on the Elm side the type definition has the same modifications applied:

type FooType =
  Enum { values: (List String) }
  ...

Which causes issues, especially with constructors like FooTypeInt, which ends up being defined as just Int.

Is there a way to apply constructorTagModifer only to the json encoding/decoding?

Support for simple phantom types

Currently, if we have a simple phantom type like this in Haskell:

newtype Id a = Id { unId :: Text }

there exists a valid elm equivalent of:

type Id a = Id { unId : String }

However, trying to derive it with deriveElmDef fails with the error message:

Oops, can only derive data and newtype, not this: NewtypeD [] Main.Id [KindedTV a_6989586621679074905 StarT] Nothing (RecC Main.Id [(Main.unId,Bang NoSourceUnpackedness NoSourceStrictness,ConT Data.Text.Internal.Text)]) []

Redefining the initial definition of Id to use data instead of newtype and passing in a dummy type in the DefineElm clause like DefineElm (Proxy @(Id Text)) will produce the following elm code which is invalid:

type alias Id a =
   { unId: String
   }

and fails with the error message:

Type alias `Id` cannot have unused type variables: a

12|>type alias Id a =
13|>   { unId: String
14|>   }

You probably need to change the declaration like this:

type alias Id = ...

What is the current best strategy for sharing simple phantom types across Haskell and Elm?

Lambda paramaters fail Elm 0.19 shadowing rules

elm-bridge generates

jsonEncUserInput : UserInput -> Value
jsonEncUserInput  val =
    let keyval v = case v of
                    Disconnected  -> ("Disconnected", encodeValue (Json.Encode.list identity []))
                    KeyDown v1 -> ("KeyDown", encodeValue (jsonEncKey v1))
                    KeyUp v1 -> ("KeyUp", encodeValue (jsonEncKey v1))
                    MoveFromTo v1 v2 -> ("MoveFromTo", encodeValue (Json.Encode.list identity [(\(v1,v2) -> Json.Encode.list identity [(Json.Encode.int) v1,(Json.Encode.int) v2]) v1, (\(v1,v2) -> Json.Encode.list identity [(Json.Encode.int) v1,(Json.Encode.int) v2]) v2]))
                    MoveNSizedPieceTo v1 v2 -> ("MoveNSizedPieceTo", encodeValue (Json.Encode.list identity [Json.Encode.int v1, (\(v1,v2) -> Json.Encode.list identity [(Json.Encode.int) v1,(Json.Encode.int) v2]) v2]))
    in encodeSumObjectWithSingleField keyval val

for Haskell types like

data UserInput
  = Disconnected
  | KeyDown Key
  | KeyUp Key
  | MoveFromTo (Int, Int)
               (Int, Int)
  | MoveNSizedPieceTo Int
                      (Int, Int)

which causes Elm 0.19 compiler errors such as

-- SHADOWING ------------- ./Communication/WebSocket/Compiled/ClientToServer.elm

These variables cannot have the same name:

55|                     MoveFromTo v1 v2 -> ("MoveFromTo", encodeValue (Json.Encode.list identity [(\(v1,v2) -> Json.Encode.list identity [(Json.Encode.int) v1,(Json.Encode.int) v2]) v1, (\(v1,v2) -> Json.Encode.list identity [(Json.Encode.int) v1,(Json.Encode.int) v2]) v2]))
                                   ^^                         ^^
Think of a more helpful name for one of them and you should be all set!

Note: Linters advise against shadowing, so Elm makes “best practices” the
default. Read <https://elm-lang.org/0.19.0/shadowing> for more details on this
choice.

Since at least one issue has been closed in the past for 0.19 support (#37), I had assumed the library was ready for Elm 0.19 -- I am not sure what your expectation of 0.19 compatibility actually is.

Strange linking error on OS X

I'm having an issue using this elm-bridge and hlibsass. I have built a testing repo here https://github.com/dunnl/elm-bridge-iss20. It has something to do with the TemplateHaskell. The code looks like this:

{-# language TemplateHaskell #-}
{-# language DeriveGeneric     #-}
{-# language RecordWildCards   #-}

module Main where

import Bindings.Libsass
import Elm.Derive
import GHC.Generics

data Test = Test { content :: String, number :: Int}
  deriving (Generic)

deriveBoth defaultOptions ''Test

main :: IO ()
main = print "Test"

stack build gives me errors like this:

ghc: 
lookupSymbol failed in relocateSection (RELOC_GOT)
/Users/dunnl/.stack/snapshots/x86_64-osx/lts-9.5/8.0.2/lib/x86_64-osx-ghc-8.0.2/hlibsass-0.1.6.1-5YgnetLqItEKQRTonDV5HP/libsass.a: unknown symbol `___dso_handle'
ghc: Could not on-demand load symbol 
'__ZN4Sass10VectorizedINS_10SharedImplINS_15Simple_SelectorEEEE20adjust_after_pushingES3_'

ghc: 
lookupSymbol failed in relocateSection (relocate external)
/Users/dunnl/.stack/snapshots/x86_64-osx/lts-9.5/8.0.2/lib/x86_64-osx-ghc-8.0.2/hlibsass-0.1.6.1-5YgnetLqItEKQRTonDV5HP/libsass.a: unknown symbol `__ZN4Sass15read_css_stringERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE'
ghc: Could not on-demand load symbol '__ZN4Sass15String_ConstantC2ENS_11ParserStateEPKc'

The problem does not go away after nuking .stack-work/ and even after deleting stack's snapshots in my home folder. I am not sure if the problem is unique to hlibsass, but it has given people problems on OS X before. I'm also not sure that the problem is unique to elm-bridge either, but I can't reproduce the error with simple TH expressions. Removing either deriveBoth or import Bindings.Libsass (and removing the dep. from the cabal file) fixes the problem. I cannot reproduce the issue on my Arch linux box.

Possibly related: GHC #11617, hlibsass #5

This sounds like it's not elm-bridge's "fault", but I don't know enough about template haskell to understand the problem. I guess TH changes the parameters of the linking stage?

A few bugs

Here are a few bugs I uncovered:

  • This should be \\v instead of \v
  • On the same line, this isn't properly parsed by my elm compiler in many cases. It needs proper indentation.
  • There are several cases where matching closing parens are omited, and even the tests don't parse.

I am currently working on this module, with an eye on parameterizing it with the Options type from aeson, so that my instances will be compatible even in the presence of strange customization. I added quite a bit of code (support for alternative sum encoding schemes, sum types with records, map-like structures). It is pretty much out of the scope of your project because of the dependency on aeson, but let me know if you would be interested in merging some of it.

Good way to deal with Persistent's Entity?

Im adapting to Yesod Persistent. Thus my old Game type becomes "Entity Game" that is constructed as "Entity GameId Game" where type GameId = Key Game (or something like that).

ive managed to make stuff work by adding a wrapper that can be incorpoarated in elm-bridge, but it feels clumsy

data Ent a b = Ent { _key :: a, _val :: b } deriving (Show,Generic)

Incase you are familiar with Persistent, how would one incorporate encoding of (nested) entity types in elm-bridge.

trying to get :

deriveBoth defaultOptions { fieldLabelModifier = drop 1} ''PS.Entity

..to compile gives :

Can't derive this sum: ForallC [] [AppT (ConT Database.Persist.Class.PersistEntity.PersistEntity) (VarT record_7566047373982557936)] (RecC Database.Persist.Class.PersistEntity.Entity [(Database.Persist.Class.PersistEntity.entityKey,Bang NoSourceUnpackedness NoSourceStrictness,AppT (ConT Database.Persist.Class.PersistEntity.Key) (VarT record_7566047373982557936)),(Database.Persist.Class.PersistEntity.entityVal,Bang NoSourceUnpackedness NoSourceStrictness,VarT record_7566047373982557936)])

How to deal with # (magic hash) in Haskell data types?

I started to learn about Servant from the Building an API with Servant! tutorial. When I later got interested in Elm I tried to automatically generate Elm code for this Servant API which uses Int64 and I discovered that Int64 is defined as a primitive unboxed Haskell type:

data {-# CTYPE "HsInt64" #-} Int64 = I64# Int#

, which make use of # (magic hashes).

In the generated Elm module the Haskell type Int64 is represented by the following Elm type:

type Int64  =
    I64# Int#

, which is not valid Elm syntax:

-- UNEXPECTED SYMBOL  /Users/XXX/elm-frontend/src/Derived.elm

I got stuck on this symbol:

14|     I64# Int#
           ^
It is not used for anything in Elm syntax. Try removing it?

I've initially posted a question on Stack Overflow about this. The obvious solution is to simply avoid data types with magic hashes in the Servant API. But, even if Elm may not have an analogue to boxed vs unboxed types, I cannot help wondering if it wouldn't be useful to be able to generate Elm code for arbitrary Servant APIs including data types with magic hashes. In this example, if the ranges of Haskell Int and Elm Int are the same, the magic hashes could simply be removed and the Haskell Int# be represented by Int in Elm:

type Int64  =
    I64 Int

There may be more to this topic than I currently understand and there are probably a lot to consider to make this work for all general uses of magic hashes in Haskell data types. Anyway, since I stumbled upon this I thought I should create a GitHub issue.

Dict serialization escape key string

Hello,

First things first, thank you for this great lib, it helps a lot!!
I have a minor question/issue regarding Dict serialization.

For Dict, encodeMap is used

ETyApp (ETyApp (ETyCon (ETCon "Dict")) key) value -> "(encodeMap (" ++ jsonSerForType key ++ ") (" ++ jsonSerForType value ++ "))"

Because of encodeMap, if the key is a String, the json key will be escaped.
eg:

{ "\"key\"" : "value" }

Is this voluntary? It seems more logical to use Json.Encode.dict to me but maybe I'm missing something...

Mismatch in format used by elm-bridge and Aeson

My setup is that I have a websocket server running in Haskell, accepting commands encoded into JSON by elm-bridge's encoders on the client-side, and decoded by Aeson on the server-side.

On the server, in Haskell I have my data types defined as follows:

{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}

module Domain.Data where

import GHC.Generics
import Data.Aeson

data WebSocketMessage = WebSocketMessage String deriving (Eq, Show, Generic, ToJSON, FromJSON)
data WebSocketCommand = WebSocketCommand Command deriving (Eq, Show, Generic, ToJSON, FromJSON)

data Id = Id String deriving (Eq, Show, Ord, Generic, ToJSON, FromJSON)
data EditDone = EditDone Id DoneState DoneState deriving (Eq, Show, Generic, ToJSON, FromJSON)
data DoneState   = Done | NotDone deriving (Eq, Show, Generic, ToJSON, FromJSON)

data Command
    = EditDoneCommand EditDone
    | OtherCommands

and these are decoded in the server via:

    let mCmd :: Maybe WebSocketCommand = Json.decode msg

Note that I'm using the Generic, ToJSON, and FromJSON automatic derivations for the server-side decoding via Aeson.

Also in Haskell I'm executing elm-bridge, like so:

{-# LANGUAGE TemplateHaskell #-}
import Elm.Derive
import Elm.Module

import Data.Proxy

import Domain.Data

deriveElmDef defaultOptions ''EditDone
deriveElmDef defaultOptions ''Command
deriveElmDef defaultOptions ''Id
deriveElmDef defaultOptions ''DoneState

main :: IO ()
main = do
    putStrLn $ makeElmModule "Domain.Data"
        [ DefineElm (Proxy :: Proxy EditDone)
        , DefineElm (Proxy :: Proxy Command)
        , DefineElm (Proxy :: Proxy Id)
        , DefineElm (Proxy :: Proxy DoneState)

Note that I'm only running "deriveElmDef" as the Aeson derivations are already done separately. This took a bit of working out on my part as I don't think it's documented, so it may well be that I got this bit wrong; I couldn't get my program to compile any other way though!

Right, now to the meat; I added some tracing to my server and I can see that I receive JSON in the form:

{"EditDoneCommand":["foo","NotDone","Done"]}

But when Aeson decodes it I get a Nothing. So I added an output for Aeson's encoding, and it turns out that Aeson outputs a different format:

{"tag":"EditDoneCommand","contents":["foo","NotDone","Done"]}

Which looks like a longer form.

Given that I'm not familiar with Aeson, have I misconfigured something in my enthusiasm to get the thing compiling? Do you know how I can remedy this situation?

Thanks in advance for any advice!

PS. I have elm-bridge 0.4.0 and Aeson 0.11.2.1 installed.

Build failure with GHC 8

> /tmp/stackage-build8$ stack unpack elm-bridge-0.3.0.0
Unpacked elm-bridge-0.3.0.0 to /tmp/stackage-build8/elm-bridge-0.3.0.0/
> /tmp/stackage-build8/elm-bridge-0.3.0.0$ runghc -clear-package-db -global-package-db -package-db=/home/stackage/work/builds/nightly/pkgdb Setup configure --package-db=clear --package-db=global --package-db=/home/stackage/work/builds/nightly/pkgdb --libdir=/home/stackage/work/builds/nightly/lib --bindir=/home/stackage/work/builds/nightly/bin --datadir=/home/stackage/work/builds/nightly/share --libexecdir=/home/stackage/work/builds/nightly/libexec --sysconfdir=/home/stackage/work/builds/nightly/etc --docdir=/home/stackage/work/builds/nightly/doc/elm-bridge-0.3.0.0 --htmldir=/home/stackage/work/builds/nightly/doc/elm-bridge-0.3.0.0 --haddockdir=/home/stackage/work/builds/nightly/doc/elm-bridge-0.3.0.0 --flags=
Configuring elm-bridge-0.3.0.0...
> /tmp/stackage-build8/elm-bridge-0.3.0.0$ runghc -clear-package-db -global-package-db -package-db=/home/stackage/work/builds/nightly/pkgdb Setup build
Building elm-bridge-0.3.0.0...
Preprocessing library elm-bridge-0.3.0.0...
[1 of 7] Compiling Elm.Versions     ( src/Elm/Versions.hs, dist/build/Elm/Versions.o )
[2 of 7] Compiling Elm.Utils        ( src/Elm/Utils.hs, dist/build/Elm/Utils.o )
[3 of 7] Compiling Elm.TyRep        ( src/Elm/TyRep.hs, dist/build/Elm/TyRep.o )
[4 of 7] Compiling Elm.Json         ( src/Elm/Json.hs, dist/build/Elm/Json.o )

src/Elm/Json.hs:111:23: warning: [-Wunused-matches]
    Defined but not used: ‘o’

src/Elm/Json.hs:112:22: warning: [-Wunused-matches]
    Defined but not used: ‘os’
[5 of 7] Compiling Elm.TyRender     ( src/Elm/TyRender.hs, dist/build/Elm/TyRender.o )
[6 of 7] Compiling Elm.Module       ( src/Elm/Module.hs, dist/build/Elm/Module.o )
[7 of 7] Compiling Elm.Derive       ( src/Elm/Derive.hs, dist/build/Elm/Derive.o )

src/Elm/Derive.hs:191:10: error:
    • The constructor ‘DataD’ should have 6 arguments, but has been given 5
    • In the pattern: DataD _ _ tyVars constrs _
      In a case alternative:
          DataD _ _ tyVars constrs _
            -> case constrs of {
                 [] -> fail "Can not derive empty data decls"
                 [RecC _ conFields] -> deriveAlias opts name tyVars conFields
                 _ -> deriveSum opts name tyVars constrs }
      In a stmt of a 'do' block:
        case tyCon of {
          DataD _ _ tyVars constrs _
            -> case constrs of {
                 [] -> fail "Can not derive empty data decls"
                 [RecC _ conFields] -> deriveAlias opts name tyVars conFields
                 _ -> deriveSum opts name tyVars constrs }
          NewtypeD _ _ tyVars (RecC _ conFields) _
            -> deriveAlias opts name tyVars conFields
          TySynD _ vars otherTy -> deriveSynonym opts name vars otherTy
          _ -> fail
                 ("Oops, can only derive data and newtype, not this: "
                  ++ show tyCon) }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.