genuinequestion
genuinequestion

Reputation: 31

pass type to decode json in haskell

I think I'm going about this problem in a fundamentally incorrect way, but I'm not sure how to make an elegant solution in Haskell.

I would like to write a function which parses a string of JSON into some Haskell type. However, I don't know how to pass the type into my function (which I don't think I can do).

For example, I would like to do something like this:

data Foo = Foo { _a :: String } deriving (Generic, ToJSON, FromJSON)
data Bar = Bar { _b :: String } deriving (Generic, ToJSON, FromJSON)

parseSomething :: (FromJSON a) => a -> Maybe a
parseSomething a = (decode "..some json string...") :: Maybe a

Is this possible, or am I thinking about the problem incorrectly?

At the moment, I receive a type deduction error:

    • Could not deduce (FromJSON a1) arising from a use of ‘decode’
      from the context: FromJSON a
        bound by the type signature for:
                   foo :: forall a. FromJSON a => a -> Maybe a
        at src/Plumbing/Types.hs:60:1-35
      Possible fix:
        add (FromJSON a1) to the context of
          an expression type signature:
            forall a1. Maybe a1
    • In the expression: decode "{\"_a\":\"foo\"}" :: (Maybe a)
      In an equation for ‘foo’:
          foo a = decode "{\"_a\":\"foo\"}" :: (Maybe a)
   |
61 | foo a = decode "{\"_a\":\"foo\"}" :: (Maybe a)

Upvotes: 3

Views: 168

Answers (1)

Henri Menke
Henri Menke

Reputation: 10939

You can use the type applications extension for this:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}

import Data.Aeson
import GHC.Generics

data Foo = Foo { _a :: String } deriving (Show, Generic, ToJSON, FromJSON)
data Bar = Bar { _b :: String } deriving (Show, Generic, ToJSON, FromJSON)

parseSomething :: (FromJSON a) => Maybe a
parseSomething = decode "{ \"_a\": \"Hello\" }"

main :: IO ()
main = putStrLn $ show (foo, bar)
  where
    foo = parseSomething @Foo
    bar = parseSomething @Bar

but honestly I see zero benefit of being able to write

foo = parseSomething @Foo
bar = parseSomething @Bar

over

foo = parseSomething :: Maybe Foo
bar = parseSomething :: Maybe Bar

Upvotes: 4

Related Questions