Это может быть сложным, что нужно сделать, но это выполнимо в некоторых контекстах. В основном, если они являются монадами, вы можете видеть внутри (например, Maybe
или монаду, которую вы написали), тогда вы можете определить такую операцию.
Одна вещь, которая иногда весьма удобна (в GHC), заключается в том, чтобы заменить класс Monad
на свой собственный. Если вы определяете return, >>=, fail
, вы все равно сможете использовать нотацию do
. Вот пример того, что может быть как то, что вы хотите:
class Compose s t where
type Comp s t
class Monad m where
return :: a -> m s a
fail :: String -> m a
(>>=) :: (Compose s t) => m s a -> (a -> m t b) -> m (Comp s t) b
(>>) :: (Compose s t) => m s a -> m t b -> m (Comp s t) b
m >> m' = m >>= \_ -> m'
Вы можете контролировать, какие типы могут быть упорядочены с помощью оператора связывания, на основании которых экземпляры Compose
вы определили. Естественно, вы часто захотите Comp s s = s
, но вы также можете использовать это, чтобы определить всевозможные сумасшедшие вещи.
Например, возможно, у вас есть некоторые операции в вашей монаде, за которыми абсолютно не могут следовать какие-либо другие операции. Хотите сделать это статически? Определите пустой тип данных data Terminal
и не укажите экземпляры Compose Terminal t
.
Этот подход не подходит для переноса из (скажем) Maybe
в IO
, но его можно использовать для переноса данных определенного типа на предмет того, что вы делаете.
Если вы действительно хотите изменить монады, вы можете изменить определение класса выше в нечто вроде
class Compose m n where
type Comp m n
(>>=*) :: m a -> (a -> n b) -> (Compose m n) b
class Monad m where
return :: a -> m a
fail :: String -> m a
(>>=) :: Compose m n => m a -> (a -> n b) -> (Compose m n) b
m >>= f = m >>=* f
(>>) :: Compose m n => m a -> (n b) -> (Compose m n) b
m >> n = m >>=* \_ -> n
Я использовал прежний стиль для полезных целей, хотя я полагаю, что эта последняя идея может также быть полезными в определенных контекстах.
Если это так, то 'M' и' M'' не являются (просто) монадами. – kennytm
... и почему вы хотите конвертировать одну монаду в другую? Я не думаю, что безопасно конвертировать IO в Maybe, например. Однако можно составить монады ('IO (Maybe a)'). – kennytm
Конвертировать в разные Монады, поэтому я могу сделать больше различных вычислений, интуитивно. но, возможно, это не так полезно, не так ли? Я ищу примеры, чтобы показать, что есть причина делать подобные вещи. – Rn2dy