I'm just getting into my first real Haskell project of size (a web app), and I'm starting to run into issues with types from 3rd party libraries leaking all over my code. Here is a quick example:
Parser module imports
Test.Parsec, and the exports a function (
parseConfig) that returns
Either ParseError DbConfig, where
ParseError is a data type defined in the
Parsec library (
DbConfig is a custom data type for my app, not shown for brevity).
-- Parser.hs module Parser where import Text.Parsec parseConfig :: String -> Either ParseError DbConfig parseConfig = parse ...
Later, I want to use my
parseConfig function, but in order to use it, I have to import
Text.Parsec again so that I have access to the
-- Api.hs module Api where import Parser import Text.Parsec getConfigFromBody :: Object -> Either ParseError DbConfig getConfigFromBody = parseConfig . (...)
This is not only a hassle as far as managing imports goes, but also a poor separation of concerns, so right of the bat I know this isn't the best way to do it. My question is, what is the best practice for managing this issue? Would making a type synonym be ideal?
type ConfigParseError = ParseError parseConfig :: String -> Either ConfigParseError DbConfig parseConfig = parse ...
This seems reasonable insofar as keeping the
Parsec the dependency internal to my
Parser module, but aliasing library types seems like a strange pattern to use by default.
So my question is, how do larger Haskell apps or libraries handle this? Is there a general technique for managing data types from 3rd party libraries?