Dire che mi piacerebbe costruire sottotipi che soddisfano determinati invarianti senza l'aiuto di strumenti esterni come LiquidHaskell (idealmente voglio farlo anche senza typeclass). Qual è il modo più elegante per farlo? Finora ho provato quanto segue:Convalida a livello di tipo
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
suppongo che se non esportare il costruttore "Nome" dal modulo, avrò una soluzione di lavoro, perché l'unico modo per costruire un elemento di tipo sarebbe attraverso la funzione makeValidated.
Tuttavia compilatore si lamenta in quanto tale:
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
Come posso risolvere il problema?
Ho provato a modificare il mio codice come segue, ma io sono sempre lo stesso messaggio di errore. Che cosa sto facendo di sbagliato? 'dati proxy a = Proxy' ' '' classe validato un WHERE' 'tipo sottostante a' ' convalidare :: un proxy -> Alla base di un -> Bool' 'costruire :: Alla base di un -> un ' ' use :: a -> Underlying a' '' 'makeValidated :: Validated a => Sottostante a -> Forse a' ' makeValidated u = se validate (Proxy :: Proxy a) u' 'then Just (costruisci u) ' ' else Nothing' – NioBium
@NioBium È necessario usare 'makeValidated :: forall a. Convalidato a => ... 'e abilita l'estensione di linguaggio' ScopedTypeVariables'. Probabilmente una scelta migliore potrebbe essere quella di rimuovere 'validate, construct' dalla classe e aggiungere' makeValidated' invece nella classe. – chi