Monad“绑定”功能问题

时间:2010-07-16 18:34:50

标签: haskell monads

如果我像这样定义“bind”函数:

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

如果我希望结果是新的Monad类型,或者我应该使用相同的Monad但是在同一个Monad框中使用b,那么这个定义会帮助我吗?

4 个答案:

答案 0 :(得分:7)

正如我在评论中提到的,我不认为可以为一般的monad安全地定义这样的操作(例如M = IOM' = Maybe)。

但是,如果M可以安全地转换为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),...注意对于任何monad都没有通用的convert方法。

答案 1 :(得分:1)

这个定义不仅没有帮助,而且会严重混淆未来的代码读者,因为它会打破使用它的所有期望。

例如,M和M'都应该是Monads吗?如果是这样,那么它们是如何定义的?请记住:>>=的定义是Monad定义的一部分,并且在任何地方用于定义其他使用Monad的函数 - 除了returnfail之外的每个函数。

另外,您可以选择使用哪种M和M',还是选择计算机?如果是这样,那么你如何选择?它是否适用于任何两个Monad实例,或者是否有你想要的Monad子集 - 或者M的选择是否决定M的选择?

可以创建一个像你所写的一样的函数,但肯定是很多>>=更复杂,并且它会产生误导,残忍,并且可能是灾难性的。试着把你的功能塞进>>=的衣服里。

答案 2 :(得分:1)

这可能是一件复杂的事情,但在某些情况下它是可行的。基本上,如果它们是monad你可以在里面看到(例如Maybe或你写过的monad),那么你可以定义这样的操作。

有时候(在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,但你也可以用它来定义各种疯狂的东西。

例如,也许你的monad中有一些操作,绝对不能跟随任何其他操作。想要静态执行吗?定义空数据类型data Terminal,不提供Compose Terminal t的实例。

这种方法不适合从(例如)Maybe转换为IO,但它可用于传输有关您正在做的事情的某些类型级数据。

如果您确实想要更改monad,可以将上面的类定义修改为

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

我已经将前一种风格用于有用的目的,尽管我认为后一种观点在某些情况下也可能有用。

答案 3 :(得分:0)

您可能需要查看Oleg的这个示例:http://okmij.org/ftp/Computation/monads.html#param-monad