Reading String into Custom DataType

Suppose we need to store a custom data object into a database and be able to read it back.

data Country = USA | MEXICO
instance Show Country where
  show USA = "United States"
  show MEXICO = "Mexico"

Suppose after quering a database, we get a string “Mexico”. How to parse it into a Country datatype?

For example, for an integer, I would do the following:

read “2” :: Int

You can implement the Read type class for your type. If the exact representation doesn’t matter to you, you can derive these instances:

data Country
  = USA
  | Mexico
  deriving (Read, Show)
>>> show USA
"USA"
>>> read "USA" :: Country
USA
1 Like

I would not use read because it can fail. How about:

{-# LANGUAGE OverloadedStrings #-}

import qualified Data.Aeson as Aeson
import Data.Text.Lazy (Text, fromStrict)

toCountry :: Text -> Maybe Country
toCountry text =
  case text of
    "United States" ->
      Just USA
    "Mexico" ->
      Just MEXICO
    _ ->
      Nothing

and/or with Aeson:

instance Aeson.FromJSON Country where
  parseJSON (Aeson.String s) =
    maybe mempty return (toCountry (fromStrict s))
  parseJSON _ = mempty

(I’m very new to haskell, so I could be totally wrong about this)

There is a variant that does not throw errors: Text.Read.readMaybe

4 Likes

Opaleye has exactly this feature by the way:

https://hackage.haskell.org/package/opaleye-0.9.2.0/docs/Opaleye-Experimental-Enum.html