У меня есть что-то похожее на этот класс в моем коде. В моей ситуации нет смысла добавлять a' в качестве еще одного параметра к классу Foo.
class Foo a where
type FCtx a a' :: Constraint
type FCtx a a' = ()
f :: (FCtx a a') => a -> a'
data D b = D b
instance (Integral b) => Foo (D b) where
-- the next line does not compile because b' does not appear on the LHS
type FCtx (D b) a' = (a' ~ D b', Integral b')
f (D x) = D $ fromIntegral x
Для этого конкретного экземпляра Foo
я хочу, чтобы a'
был связан таким образом. Единственный способ, который я придумал, чтобы заставить эту работу работать, - это добавить «фиктивный» класс с синонимом «очевидного» типа:
class DClass d where
type DType d
instance DClass (D b) where
type DType (D b) = b
Экземпляр Foo
теперь становится:
instance (Integral b) => Foo (D b) where
type FCtx (D b) a' = (a' ~ D (DType a'), Integral (DType a'))
f (D x) = D $ fromIntegral x
Проблема в том, что мне пришлось создать целый класс (и экземпляр) для моего конкретного типа данных только для того, чтобы выразить синоним/функциональную зависимость типа, которую (D b) определяет b. У меня не будет других экземпляров этого класса, потому что я всегда хочу, чтобы DType a'
означало параметр типа для D b
.
Вместо этого я хотел бы сделать что-то вроде:
type DParam (D b) = b
instance (Integral b) => Foo (D b) where
type FCtx (D b) a' = (a' ~ D (DParam a'), Integral (DParam a'))
f (D x) = D $ fromIntegral x
или, может быть, даже какой-то более приятный способ выразить это ограничение без использования синонимов типов вообще. Кажется глупым, что я должен быть вынужден создать (открытый) класс с синонимом типа с одним экземпляром только для этого, и небезопасно, что другие потенциально могут создать новые экземпляры, которые я не планировал.
По крайней мере, не будет ли какой-то канонический способ превратить «синоним типа, соответствующего шаблону», в класс/экземпляр DClass
выше?