Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aeson: parse enumerated data types

How can I declare an instance of FromJSON of the following data type:

data Privacy = Everyone | 
           AllFriends | 
           FriendsOfFriends | 
           Self

So that the following string to enumerated data type is honored:

"EVERYONE" -> Everyone
"ALL_FRIENDS" -> AllFriends
"FRIENDS_OF_FRIENDS" -> FriendsOfFriends
"SELF" -> Self
_ -> Parsing error

A possible solution is hinted here, but I cannot make that code compile.

Thanks!

like image 468
Damian Nadales Avatar asked Nov 22 '14 10:11

Damian Nadales


2 Answers

This way involves less boilerplate, but it may not be as efficient due to the T.unpack

data Privacy = Everyone | AllFriends | FriendsOfFriends | Self deriving (Read, Show)

instance FromJSON Privacy where
  parseJSON (String s) = fmap read (pure $ T.unpack s)
  parseJSON _ = mzero
like image 90
sportanova Avatar answered Nov 16 '22 07:11

sportanova


The FromJSON definition should read:

instance FromJSON Privacy where
     parseJSON (Object v) = createPrivacy <$> (v .: "value")

Complete working example:

{-# LANGUAGE OverloadedStrings #-}

import Data.Text
import Data.Aeson
import Control.Applicative
import Control.Monad

data Privacy = Everyone |
               AllFriends |
               FriendsOfFriends |
               Self
  deriving (Show)

instance FromJSON Privacy where
     parseJSON (Object v) = createPrivacy <$> (v .: "value")
     parseJSON _          = mzero

createPrivacy :: String -> Privacy
createPrivacy "EVERYONE" = Everyone
createPrivacy "ALL_FRIENDS" = AllFriends
createPrivacy "FRIENDS_OF_FRIENDS" = FriendsOfFriends
createPrivacy "SELF" = Self
createPrivacy _ = error "Invalid privacy setting!"

main = do
    let a = decode "{\"value\":\"ALL_FRIENDS\",\"foo\":12}" :: Maybe Privacy
    print a
like image 2
ErikR Avatar answered Nov 16 '22 06:11

ErikR