It’s advisable to use newtype
and create new types, instead of using basic types over and over again. This lets you tell apart FirstName
, LastName
and FavouriteMusic
.
There are several instances that one ends up writing often when using newtypes: ToJSON
, FromJSON
, PersistField
, PersistFieldSql
and IsString
. Some template haskell can save a lot of repetitive writing here. There’s an initial implementation in legislation branch. Eventually it’ll be in the master branch too, when other things in legislation branch are ready.
Module Templates
has a single exported function, makeDomainType
, which is used to create a newtype definition and instances mentioned before. Invoke it as any template haskell: $(makeDomainType "PlanetName" ''Text)
. First parameter is name of the new type to create and the second one is the type of the wrapped value. Currently only Int
and Text
are supported. This will create following code:
newtype PlanetName
= MkPlanetName {_unPlanetName :: Text}
deriving (Show, Read, Eq)
instance IsString PlanetName where
fromString = (MkPlanetName . fromString)
instance ToJSON PlanetName where
toJSON = (toJSON . _unPlanetName)
instance FromJSON PlanetName where
parseJSON = (withText "PlanetName") (return . MkPlanetName)
instance PersistField PlanetName where
toPersistValue (MkPlanetName s) = PersistText s
fromPersistValue (PersistText s) = (Right $ MkPlanetName s)
fromPersistValue _ = Left "Failed to deserialize"
instance PersistFieldSql PlanetName where
sqlType _ = SqlString
In case of Int
, IsString
instance will not be generated.
If there are errors in generated code, you can dump the crated code in file for further examination, by adding --ddump-splices --ddump-to-file
to ghc options. I often run tests with command stack test --flag sky:dev --flag sky:library-only --ghc-options "--ddump-splices --ddump-to-file"
. Dumped files can be found under Cabal work directory: .stack-work/dist/<architecture>/build/src
.