Excuse me for my extremely limited Haskell-fu.
I have a series of data
types, defined in different modules, that are structured the same way:
-- in module Foo
data Foo = Foo [Param]
-- in module Bar
data Bar = Bar [Param]
-- * many more elsewhere
I'd like to have a set of functions that operate on the list of params, eg to add and remove elements from the list (returning a new Foo
or Bar
with a different list of params, as appropriate).
As far as I can tell, even if I create a typeclass and create instances for each type, I'd need to define all of these functions each time, ie:
-- in some imported module
class Parameterized a where
addParam :: a -> Param -> a
-- ... other functions
-- in module Foo
instance Parameterization Foo where
addParam (Foo params) param = Foo (param:params)
-- ... other functions
-- in module Bar
instance Parameterization Bar where
-- this looks familiar...
addParam (Bar params) param = Bar (param:params)
-- ... other functions
This feels tedious -- far past the degree where I start thinking I'm doing something wrong. If you can't pattern match regardless of constructor (?) to extract a value, how can boilerplate like this be reduced?
To rebut a possible line of argument: yes, I know I could simply have one set of functions (addParam
, etc), that would explicitly list each constructor and pattern match put the params -- but as I'm building this fairly modularly (the Foo
and Bar
modules are pretty self-contained), and I'm prototyping a system where there will be dozens of these types, a verbose centralized listing of type constructors seems... wrong.
It's quite possible (probable?) that my approach is simply flawed and that this isn't anywhere near the right way to structure the type hierarchy anyhow -- but as I can't have a single data
type somewhere and add a new constructor for the type in each of these modules (?) I'm stumped at how to get a nice "plugin" feel without having to redefine simple utility functions each time. Any and all kind suggestions gladly accepted.
You can have default implementations of functions in a typeclass, e.g.
class Parameterized a where
params :: a -> [Param]
fromParams :: [Param] -> a
addParam :: a -> Param -> a
addParam x par = fromParams $ par : params x
-- ... other functions
instance Parameterized Foo where
params (Foo pars) = pars
fromParams = Foo
However, your design does look suspicious.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With