I want to build a large schema in Haskell. The constituents take parameters and the parameters are constrained. As an example, I might decide that a circle takes one parameter called Radius, which is constrained to be non-negative. I will define the parameters globally, since each can be used by multiple constituents. There may be hundreds of parameters, and many will have long, difficult-to-type names.
I have a solution of sorts, but the parameter declarations are repetitive and I'd like to simplify them. My criteria for "simple" is just to minimize the number of times a parameter name must be typed. One part of this is to simplify the parameter definitions themselves. Another is to avoid typing parameter names when creating data objects, if possible. So, one should be able to construct a Circle without actually typing "Radius".
The code is below, followed by a few more specific questions. Thanks in advance for any help!
data Constraint = Constraint
test :: Float -> Constraint -> Bool
test _ _ = undefined
--
nonnegative :: Constraint
nonnegative = undefined
--
data Expr = Constant Float -- | Variable String | Add Parameter Parameter ...
eval (Constant x) = x
--
class Parameter a where
value :: a -> Float
constraint :: a -> Constraint
validate :: a -> Bool
validate x = test (value x) (constraint x)
-- Schema. Expecting dozens of constituents with many parameters existing
-- in complex relationships.
data Shape = Circle Radius
--
-- There may be hundreds of parameters like Radius, many with long,
-- difficult-to-type names.
data Radius = Radius Expr
instance Parameter Radius where
constraint _ = nonnegative
value (Radius r) = eval r
Can you suggest a better way to structure this code?
I think Template Haskell could be used to define a parameter (like Radius) without repeating the name. Would you recommend that approach?
Is it possible to write a default rule for value? Naively, I want to match the pattern
value (_ x)
, but that's not well-typed, of course. Is there some way of accomplishing the same thing?Is there a simpler way to associate a value with a type? For instance, Radius has a constraint associated with the type, but it seems unnecessary to have to construct a Radius to get its constraint. When I try to write
constraint :: Constraint
, GHC complains that the type parametera
is not used.