使用 >>= 运算符时约束中的非类型变量参数

Non type-variable argument in the constraint when using >>= operator

我有这个简单的代码:

module Matrix where

matrix :: a -> (Int, Int) -> [[a]]
matrix x (width, height) = replicate height (replicate width x)

mapMatrix :: (a -> b) -> [[a]] -> [[b]]
mapMatrix f m = map (map f) m

当我这样做时:

mapMatrix (+1) (matrix 0 (2,2))

我得到了,如预期的那样:

[[1,1],[1,1]]

可能我误解了 monads and/or 和 >>= 运算符,但我期望以下具有相同的输出:

matrix 0 (2,2) >>= mapMatrix (+1)

相反,我得到:

Non type-variable argument in the constraint: Num [b] (Use FlexibleContexts to permit this) When checking the inferred type It :: forall b. (Num [b], Num b) => [[b]]

如何使用 monad 编写 mapMatrix (+1) (matrix 0 (2,2)),这样我就可以从左到右而不是从内到外读写代码,因为正如您所想象的,我正计划使用mapMatrix 很多在同一个矩阵上,比如:

matrix ... >>= mapMatrix ... >>= mapMatrix .. >>= ...

这不是 monad 应该做的。您可能对 Data.Function 中定义的 (&) :: a -> (a -> b) 感兴趣。

matrix ... & mapMatrix ... & mapMatrix .. & ...

注意bind的签名是

(>>=) :: m a -> (a -> m b) -> m b

而且不能简单地忽略 ms。

为了完整起见,请注意实际上 可以 使用一个特定的 monad:Identity 使 bind 的行为几乎与您希望的一样。不过,它需要一些 wrapping/unwrapping 构造函数。

module Matrix where

import Data.Functor.Identity

matrix :: a -> (Int, Int) -> Identity [[a]]
matrix x (width, height) = Identity $ replicate height (replicate width x)

mapMatrix :: (a -> b) -> [[a]] -> Identity [[b]]
mapMatrix f m = Identity $ map (map f) m

那么,下面的方法也有效:

runIdentity (matrix ... >>= mapMatrix ... >>= mapMatrix .. >>= ...)