我有两种自己的数据类型如下:
Block a = NoValue | Value a
data GraphAMT a = GraphAMT_ [[Block a]]
现在,我想为他们制作实例monad,如
instance Monad Block where
return a = Value a
NoValue >>= f = NoValue
Value a >>= f = f a
fail _ = NoValue
instance Monad GraphAMT where
return a = GraphAMT_ [[Value a]]
GraphAMT_ xs >>= f = ...?
我想知道GraphAMT是否可以成为monad?如果是,那么如何构建呢?
答案 0 :(得分:3)
module MatrixOfMatrices where
data Block a = NoValue | Value a deriving Show
data GraphAMT a = GraphAMT_ [[Block a]] deriving Show
首先,你不需要Monad为每个元素添加三个,你需要fmap
,所以你应该让你的类型成为Functor的一个实例,但最简单的做法是Block
a仿函数第一:
instance Functor Block where
fmap f NoValue = NoValue
fmap f (Value a) = Value (f a)
instance Functor GraphAMT where
fmap f (GraphAMT_ xss) = GraphAMT_ . (map . map . fmap $ f) $ xss
何时
testData = GraphAMT_ [[NoValue,Value 2],[Value 56,Value 45,NoValue],[NoValue]]
然后
*MatrixOfMatrices> testData
GraphAMT_ [[NoValue,Value 2],[Value 56,Value 45,NoValue],[NoValue]]
*MatrixOfMatrices> fmap (*10) testData
GraphAMT_ [[NoValue,Value 20],[Value 560,Value 450,NoValue],[NoValue]]
正如你所希望的那样。
糟糕!我们需要定义(>>=) :: GraphAMT a -> (a -> GraphAMT b) -> GraphAMT b
。它应该采用一个函数将元素转换为矩阵,按元素应用它,然后将得到的矩阵矩阵连接成一个矩阵。
问题在于没有明显的方法可以将矩阵矩阵制作成单个矩阵,就像列表列表成为列表一样。如果元素都是数字,我们可以将它们加在一起,形成一个最大尺寸的矩阵。我们不能使用这样的解决方案,因为Monad不能使用任何有关其元素的事实,因为它们必须适用于所有类型的元素。
没有明确的方法可以做到这一点 - 你可以通过加宽每一行以适应输入矩阵的值,或者使用转置将它们放在彼此之下,将它们放在一起。您可以根据每个人所处的基质矩阵中的位置开始重叠。