Предположим, что у меня есть два монада трансформаторовPrecomposing монада трансформаторов
T1 :: (* -> *) -> * -> *
T2 :: (* -> *) -> * -> *
с экземплярами
instance MonadTrans T1
instance MonadTrans T2
и некоторые
X :: (((* -> *) -> * -> *) -> ((* -> *) -> * -> *) -> * -> *)
, такие как
newtype X t1 t2 a b = X { x :: t1 (t2 a) b }
, для которых я хотел бы определить что-то вдоль линий
instance (MonadTrans t1, MonadTrans t2) => MonadTrans (X t1 t2) where
lift = X . lift . lift
так что я могу использовать lift
поднять m a
в X T1 T2 m a
?
Проблема здесь заключается в том, что lift
s действуют на какую-нибудь монаду Monad m => m a
, которую я не могу гарантировать, что вы будете производить промежуточные шаги. Но это меня сбивает с толку. Я предоставляю реализацию lift
, поэтому могу предположить, что у меня есть Monad m => m a
, поэтому я применяю крайний правый lift
и получаю T1 m a
, о котором я ничего не знаю, но не следует ли подразумевать, что T1 m
- это Monad
? Если нет, то почему я не могу просто добавить это к ограничению моего экземпляра
instance (MonadTrans t1
, MonadTrans t2
, Monad (t2 m)) => MonadTrans (X t1 t2) where ...
Это также не работает. У меня есть интуиция, что вышеизложенным я говорю «должен ли быть t1
, t2
, m
такой, что ...», который слишком слаб, чтобы доказать, что X t1 t2
является трансформатором (работает для любых/всех Monad m
). Но для меня это все еще не имеет большого значения, может ли действующий трансформатор монады создать не монаду при применении к монаде? Если нет, я должен уйти с экземпляром MonadTrans (X t1 t2)
.
Есть ли уловка для этого, которая просто ускользает от меня или есть причина, по которой это невозможно сделать (теоретическое или ограничение того, что поддерживают текущие компиляторы).
бы импликация соответствует ничего, кроме
instance (MonadTrans t, Monad m) => Monad (t m) where
return = lift . return
a >>= b = ... # no sensible generic implementation
которая перекрывает другие экземпляры/не может предоставить конкретную привязку? Не может ли это работать с некоторой косвенностью? Изготовление returnT :: Monad m => a -> t m a
и bindT :: Monad m => t m a -> (a -> t m b) -> t m b
части MonadTrans
, чтобы можно было потом написать
instance MonadTrans (StateT s) where
lift = ...
returnT = ...
bindT = ...
...
instance (MonadTrans t, Monad m) => Monad (t m) where
return = returnT
a >>= b = a `bindT` b
Такого рода случаи в настоящее время не действует из-за перекрывание, что они тем не менее быть целесообразными, полезными?
Спасибо! Есть ли шансы на добавление? – jakubdaniel
@ jd823592 Я сомневаюсь. Это сломало бы слишком много кода - каждый экземпляр MonadTrans в мире, в том числе и в сторонних кодовых версиях сторонних разработчиков, должен был бы быть изменен для реализации члена 'transform', что не всегда тривиально - и на практике 'transform' на самом деле не оказывается настолько полезным, что выгоды не перевешивают издержки. (Я обновил свой ответ.) –
Но поскольку ни один код не использует эту функцию, возможно, будет определено определение 'transform' по умолчанию. Поскольку он не используется, он не будет нарушать код, а трансформаторы, используемые для разрыва материала с одной версии на другую, это то, что отлично подходит для версии :), поэтому даже тогда «трансформировать» для трансформаторов не нужно: (:)? Конечно, стандартные трансформаторы получат правильную реализацию. – jakubdaniel