2010-07-16 3 views
1

Если я определить функцию «привязки», как это:Монада функция «привязывать» вопрос

(>>=) :: M a -> (a -> M' b) -> M' b 

Будет ли это определение помочь мне, если я хочу, чтобы результат нового типа Монада, или я должен использовать тот же Monad, но с b в том же блоке Monad, что и раньше?

+1

Если это так, то 'M' и' M'' не являются (просто) монадами. – kennytm

+0

... и почему вы хотите конвертировать одну монаду в другую? Я не думаю, что безопасно конвертировать IO в Maybe, например. Однако можно составить монады ('IO (Maybe a)'). – kennytm

+0

Конвертировать в разные Монады, поэтому я могу сделать больше различных вычислений, интуитивно. но, возможно, это не так полезно, не так ли? Я ищу примеры, чтобы показать, что есть причина делать подобные вещи. – Rn2dy

ответ

7

Как я уже упоминал в комментарии, я не думаю, что такая операция может быть безопасно определена для общих монадов (например, M = IO, M' = Maybe).

Однако, если M безопасно конвертируемые в М», то эта привязка может быть определена как:

convert :: M1 a -> M2 a 
... 

(>>=*) :: M1 a -> (a -> M2 b) -> M2 b 
x >>=* f = convert x >>= f 

И наоборот,

convert x = x >>=* return 

Некоторые из таких методов безопасного преобразования являются maybeToList (Возможно, → []), listToMaybe ([] → Возможно), stToIO (ST RealWorld → IO), ... обратите внимание, что для любых монадов не существует общего метода convert.

+0

Кроме идентичности. – luqui

1

Мало того, что это определение не поможет, но это серьезно запутает будущих читателей вашего кода, так как оно нарушит все ожидания использования для него.

Например, M и M должны быть монадами? Если да, то как они определяются? Помните: определение >>= является частью определения Monad и используется везде для определения других функций, используемых Monad, - каждая функция, кроме return и fail.

Кроме того, вы можете выбрать, какие M и M вы используете, или компьютер? Если да, то как вы выбираете? Он работает для любых двух экземпляров Monad, или есть какой-то поднабор Monad, который вы хотите - или выбор M определяет выбор M?

Это можно сделать такую ​​функцию, что вы написали, но это, безусловно, является много сложнее, чем >>=, и это может ввести в заблуждение, жесток, и потенциально катастрофическими, чтобы попытаться втиснуть вашу функцию в >>= ' одежды.

1

Это может быть сложным, что нужно сделать, но это выполнимо в некоторых контекстах. В основном, если они являются монадами, вы можете видеть внутри (например, 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 

Я использовал прежний стиль для полезных целей, хотя я полагаю, что эта последняя идея может также быть полезными в определенных контекстах.

 Смежные вопросы

  • Нет связанных вопросов^_^