Let's say I would like to build subtypes that satisfy certain invariants without the help of external tools like LiquidHaskell (ideally I want to do this even without types). What is the most elegant way to do this? So far I have tried the following:
class Validated a where type Underlying a validate :: Underlying a -> Bool construct :: Underlying a -> a use :: a -> Underlying a makeValidated :: Validated a => Underlying a -> Maybe a makeValidated u = if validate u then Just (construct u) else Nothing newtype Name = Name String instance Validated Name where type Underlying Name = String validate str = and [ isUppercase (str !! 0 ) , all isLetter str ] construct = Name use (Name str) = str
I assume that if I do not export the "Name" constructor from the module, I will have a working solution, because the only way to build an element of this type is through makeValidated.
However, the compiler complains as such:
Could not deduce (Underlying a0 ~ Underlying a) from the context (Validated a) bound by the type signature for makeValidated :: Validated a => Underlying a -> Maybe a at validated.hs:11:18-55 NB: `Underlying' is a type function, and may not be injective The type variable `a0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) In the first argument of `validate', namely `u' In the expression: validate u In the expression: if validate u then Just (construct u) else Nothing
How to fix it?
source share