{"action":"created","issue":{"url":"https://api.github.com/repos/bos/aeson/issues/381","repository_url":"https://api.github.com/repos/bos/aeson","labels_url":"https://api.github.com/repos/bos/aeson/issues/381/labels{/name}","comments_url":"https://api.github.com/repos/bos/aeson/issues/381/comments","events_url":"https://api.github.com/repos/bos/aeson/issues/381/events","html_url":"https://github.com/bos/aeson/pull/381","id":143247546,"number":381,"title":"Add lifted typeclasses and some instances","user":{"login":"phadej","id":51087,"avatar_url":"https://avatars.githubusercontent.com/u/51087?v=3","gravatar_id":"","url":"https://api.github.com/users/phadej","html_url":"https://github.com/phadej","followers_url":"https://api.github.com/users/phadej/followers","following_url":"https://api.github.com/users/phadej/following{/other_user}","gists_url":"https://api.github.com/users/phadej/gists{/gist_id}","starred_url":"https://api.github.com/users/phadej/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/phadej/subscriptions","organizations_url":"https://api.github.com/users/phadej/orgs","repos_url":"https://api.github.com/users/phadej/repos","events_url":"https://api.github.com/users/phadej/events{/privacy}","received_events_url":"https://api.github.com/users/phadej/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-03-24T13:36:52Z","updated_at":"2016-03-28T16:01:04Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/bos/aeson/pulls/381","html_url":"https://github.com/bos/aeson/pull/381","diff_url":"https://github.com/bos/aeson/pull/381.diff","patch_url":"https://github.com/bos/aeson/pull/381.patch"},"body":"WIP, have to add rest of the instances. That should be straightforward. Comments are welcome.\r\n\r\nResolves https://github.com/bos/aeson/issues/352"},"comment":{"url":"https://api.github.com/repos/bos/aeson/issues/comments/202458878","html_url":"https://github.com/bos/aeson/pull/381#issuecomment-202458878","issue_url":"https://api.github.com/repos/bos/aeson/issues/381","id":202458878,"user":{"login":"RyanGlScott","id":2364661,"avatar_url":"https://avatars.githubusercontent.com/u/2364661?v=3","gravatar_id":"","url":"https://api.github.com/users/RyanGlScott","html_url":"https://github.com/RyanGlScott","followers_url":"https://api.github.com/users/RyanGlScott/followers","following_url":"https://api.github.com/users/RyanGlScott/following{/other_user}","gists_url":"https://api.github.com/users/RyanGlScott/gists{/gist_id}","starred_url":"https://api.github.com/users/RyanGlScott/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RyanGlScott/subscriptions","organizations_url":"https://api.github.com/users/RyanGlScott/orgs","repos_url":"https://api.github.com/users/RyanGlScott/repos","events_url":"https://api.github.com/users/RyanGlScott/events{/privacy}","received_events_url":"https://api.github.com/users/RyanGlScott/received_events","type":"User","site_admin":false},"created_at":"2016-03-28T16:01:04Z","updated_at":"2016-03-28T16:01:04Z","body":"That sounds good.\r\n\r\nAnother thorny issue: I need to lift the `KeyValue` classes to make things work when deriving `ToJSON1` or `ToJSON2`:\r\n\r\n```haskell\r\nclass KeyValue kv where\r\n    (.=) :: ToJSON v => Text -> v -> kv\r\n\r\nclass KeyValue1 kv where\r\n    liftedKeyValue :: ToJSON1 f => (v -> Value) -> Text -> f v -> kv\r\n\r\nclass KeyValue2 kv where\r\n    liftedKeyValue2 :: ToJSON2 f => (v1 -> Value) -> (v2 -> Value)\r\n                                 -> Text -> f v1 v2 -> kv\r\n```\r\n\r\nWith these, we can make instances for `Pair` (which `Data.Aeson.TH` uses internally):\r\n\r\n```haskell\r\ninstance KeyValue Pair where\r\n    name .= value = keyValuePair toJSON name value\r\n\r\ninstance KeyValue1 Pair where\r\n    liftedKeyValue tj name value = keyValuePair (liftToJSON tj) name value\r\n\r\ninstance KeyValue2 Pair where\r\n    liftedKeyValue2 tj1 tj2 name value =\r\n        keyValuePair (liftToJSON2 tj1 tj2) name value\r\n\r\nkeyValuePair :: (v -> Value) -> Text -> v -> Pair\r\nkeyValuePair tj name value = (name, tj value)\r\n```\r\n\r\nBut it's not quite as straightforward to make `KeyValue1` and `KeyValue2` instances for `Series`:\r\n\r\n```haskell\r\ninstance KeyValue Series where\r\n    name .= value = Value . Encoding $\r\n                    E.text name <> B.char7 ':' <> builder value\r\n```\r\n\r\nInstead of using `toJSON` under the hood, this instance uses `toEncoding`, so lifting this instance is a bit awkward. I can see three options:\r\n\r\n1. Don't create `KeyValue1`/`KeyValue2` instances for `Series` at all. The easiest (but most incomplete) option.\r\n2. Use `Encoding . E.encodeToBuilder . tj` to turn `tj :: v -> Value` into a function of type `v -> Encoding`. This works, but is inefficient.\r\n3. Change `ToJSON1` and `ToJSON2` to take more arguments (similarly to how `Show1`/`Show2` does it):\r\n\r\n```haskell\r\nclass ToJSON1 f where\r\n    liftToJSON :: (a -> Value) -> (a -> Encoding) -> f a -> Value\r\n    liftToEncoding :: (a -> Value) -> (a -> Encoding) -> f a -> Encoding\r\n\r\nclass ToJSON2 f where\r\n    liftToJSON2 :: (a -> Value) -> (a -> Encoding) -> (b -> Value) -> (b -> Encoding) -> f a b -> Value\r\n    liftToEncoding2 :: (a -> Value) -> (a -> Encoding) -> (b -> Value) -> (b -> Encoding) -> f a b -> Encoding\r\n```\r\n\r\nAnd update `KeyValue1`/`KeyValue2`. This would be a pretty significant change, but it would solve the above problem and allow the most customization."}}