1

My goal is to turn MyData (which has a ToJSON instance) into an Aeson.Object (I need it in the form of an Aeson.Object because I merge it with an other Aeson.Object).

I managed to achieve this goal using the following code which compiles:

myDataToAesonObject :: MyData -> Aeson.Object
myDataToAesonObject myData = aesonValueToAesonObject $ toJSON myData

aesonValueToAesonObject :: Aeson.Value -> Aeson.Object
aesonValueToAesonObject (Aeson.Object value) = value

But as a programmer who is still learning Haskell, that neither feels like a best practice to me nor do I have any ideas how to make it cleaner.

It does not feel like a best practice because somebody might misuse the aesonValueToAesonObject function and apply it (for instance) to an Aeson.Value which holds an array. I suspect this would lead to an error. Thus I would like to have something like a toJSON function which returns an Aeson.Object instead of an Aeson.Value in the first place, because it is already a known fact that myData can only be an object.

I hope you understand what I try to say.

ideaboxer
  • 3,863
  • 8
  • 43
  • 62

1 Answers1

0

Perhaps the best approach - certainly one of the most idiomatic approaches in Haskell - would be to have your aesonValueToAesonObject (and hence the other function too which uses it) return a Maybe Object:

aesonValueToAesonObject :: Aeson.Value -> Maybe Aeson.Object
aesonValueToAesonObject (Aeson.Object value) = Just value
aesonValueToAesonObject _ = Nothing

This avoids the most obvious flaw with your version - that if supplied a JSON value of the wrong "type", the program will simply crash with no possibility of recovery. By using Maybe you allow code that uses this function to determine whether the JSON representation is an object or not, and if so to extract it, otherwise to do whatever is best in the context of whatever that code is doing:

case myDataToAesonObject myValue of
  Just object -> doSomethingWithObject object
  Nothing -> somethingElseAsAppropriate
Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
  • In my specific case I would like to avoid a function like `aesonValueToAesonObject` at all because `toJSON myData` can only ever produce an `Aeson.Object` (because the type of `myData` and its `ToJSON` instance should be known for producing a JSON object only, no array, string, number,...). Then I would not get into the predicament of having to provide an alternative branch for `Nothing` (which is never expected to be reached anyway). – ideaboxer Oct 27 '22 at 19:39