Допустим, у меня есть класс:
class C a b t where
f :: (a, b) -> (t a, t b)
Теперь с этим определением я могу определить экземпляры, скажем:
(a,b) -> (Maybe a, Maybe b)
(a,b) -> ([a], [b])
Но не для (насколько я понимаю):
(a,b) -> (a,b)
(a,b) -> ((a, a), (b, b))
Вместо этого я мог бы изменить определение своего класса следующим образом:
type family T a b x
class C a b where
f :: (a, b) -> (T a b a, T a b b)
Что позволило бы мне сделать вышеперечисленное, но тогда я смог бы объявить только один f
для каждого a
и b
.
По сути, я хочу иметь возможность передать семейство типов как t
в исходном определении, которое неявно разрешается средством проверки типов, если оно известно. Я не хочу просто сделать его f :: (a, b) -> (c, d)
, поскольку я хочу сохранить инвариант, согласно которому и a
, и b
делают с ними одно и то же, поэтому swap . f
относится к тому же типу, что и f . swap
. Я думаю, что мне могут понадобиться семейства инъективных типов (из GHC 8.0), но я не уверен. Но может есть другой способ?
Identity
в первом случае и подходящий новый тип во втором (сейчас я не могу придумать ни одного стандартного). Это грубый обходной путь, но он может оказаться менее болезненным, чем продвинутый обман, который, как кажется, требуется. Между прочим, я не хочу просто делать этоf :: (a, b) -> (c, d)
, так как я хочу сохранить инвариант... очень похоже на то, что линзы lens являютсяLens s t a b
несмотря на то, что эти четыре параметра взаимозависимы (см. раздел Почему это семейство линз?). - person duplode   schedule 23.09.2015