agrafix / superrecord

Haskell: Supercharged anonymous records
BSD 3-Clause "New" or "Revised" License
83 stars 16 forks source link

How to use the ToJSON instance for Record? #8

Closed neongreen closed 7 years ago

neongreen commented 7 years ago

I am trying to define a type which has a 'Record' inside:

data Augmented x r = Augmented {
  value :: x,
  extra :: Record r }

The idea is that if you have a type x, you can add some extra fields to it (metadata, perhaps, or something GraphQL-like).

Then I want to actually define a ToJSON instance for it:

{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverloadedStrings #-}

import Data.Monoid
import SuperRecord
import Data.Aeson
import qualified Data.HashMap.Strict as HM

data Augmented x r = Augmented {
  value :: x,
  extra :: Record r }

instance (ToJSON x, ToJSON (Record r)) => ToJSON (Augmented x r) where
  toJSON (Augmented x r) =
    case toJSON x of
      Object obj -> Object (obj <> recObj)
      other      -> Object (HM.insert "value" other recObj)
    where
      Object recObj = toJSON r

Unfortunately, it doesn't work:

sr.hs:19:23-30: error: …
    • Could not deduce (RecApply
                          (SuperRecord.Sort r) (SuperRecord.Sort r) ToJSON)
        arising from a use of ‘toJSON’
      from the context: (ToJSON x, ToJSON (Record r))
        bound by the instance declaration at /tmp/sr.hs:13:10-64
    • In the expression: toJSON r
      In a pattern binding: Object recObj = toJSON r

I could add a RecApply (Sort r) (Sort r) ToJSON constraint, but Sort is not exported. The best I can do is to replace Record with Rec in my Augmented type, but then I have to sort fields manually in my type definitions because & produces records with sorted fields. Am I missing something?

agrafix commented 7 years ago

Please send a PR to export sort :-)

Am 16.09.2017 um 22:38 schrieb Artyom Kazak notifications@github.com:

I am trying to define a type which has a 'Record' inside:

data Augmented x r = Augmented { value :: x, extra :: Record r } The idea is that if you have a type x, you can add some extra fields to it (metadata, perhaps, or something GraphQL-like).

Then I want to actually define a ToJSON instance for it:

{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE OverloadedStrings #-}

import Data.Monoid import SuperRecord import Data.Aeson import qualified Data.HashMap.Strict as HM

data Augmented x r = Augmented { value :: x, extra :: Record r }

instance (ToJSON x, ToJSON (Record r)) => ToJSON (Augmented x r) where toJSON (Augmented x r) = case toJSON x of Object obj -> Object (obj <> recObj) other -> Object (HM.insert "value" other recObj) where Object recObj = toJSON r Unfortunately, it doesn't work:

sr.hs:19:23-30: error: … • Could not deduce (RecApply (SuperRecord.Sort r) (SuperRecord.Sort r) ToJSON) arising from a use of ‘toJSON’ from the context: (ToJSON x, ToJSON (Record r)) bound by the instance declaration at /tmp/sr.hs:13:10-64 • In the expression: toJSON r In a pattern binding: Object recObj = toJSON r I could add a RecApply (Sort r) (Sort r) ToJSON constraint, but Sort is not exported. The best I can do is to replace Record with Rec in my Augmented type, but then I have to sort fields manually in my type definitions because & produces records with sorted fields. Am I missing something?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

neongreen commented 7 years ago

Oh, apparently it's already exported in HEAD. Great!