I want to implement some algorithms that have a common set of parameters (in practice this is a high number, which is why I am not passing them separately into the functions):
data Parameters = Parameters {
_p1 :: A,
...
}
But each one of them has -aside from this common set- a set of parameters that only they know how to use:
data AlgorithmAParameters = AlgorithmAParameters {
_commonParameters :: Parameters,
_myp1 :: B
}
The problem here is how to write idiomatic code. I am currently using lenses, so then I can define
p1 :: Lens' AlgorithmAParameters A
p1 = commonParameters . Common.p1
And this lets me access everything the same way I would if I were using just Parameters
. The problem is that I have to do this for every algorithm that keeps its own set of parameters, and I have to be careful to import these separately, among other things.
I could go further and use type classes
class Parameters p where
p1 :: Lens' p A
...
And then implement separately
class AlgorithmAParameters p where
p1 :: Lens' p A
myp1 :: Lens' p B
Along with the AlgorithmAParameters p => AlgorithmParameters p
instance. However, this has the same kind of problem (repeated code) and ultimately leads to code that is just as misleading as the first option (plus the whole Lens'
in the type class is not very informative).
Is there an easier way to solve this?.
The classy lenses/optics technique is useful here.
The
makeClassy
Template Haskell directive will result in the following class and instance:Then for
AlgorithmParameters
Again
makeClassy
does its thing:Now, so that you can use the
CommonParameters
optics with theAlgorithmParameters
type, define the following instance: