在 Haskell 中列出 monad 实例 - 为什么在绑定操作中使用 concat?
List instance of monad in Haskell - why use concat in bind-operation?
我在这里发现了一些问题:Redefining monad list instance。我目前正试图让我的头缠绕在单子上。但是我在这里需要一些帮助,我没有将列表的实例定义作为 monad。
这是我给 monad 的列表实例的定义:
instance Monad [] where
xs >>= f = concat $ map f xs
return x = [x]
fail _ = []
我不明白,为什么我需要在绑定函数中使用 concat。
这是我对 (>>=)
:
的定义
(>>=) :: Monad m => m a -> (a -> m b) -> m b
所以我有一些 monadic 值 m a
和一个函数,取一个值 a
并产生一个 monadic 值 m b
作为参数。我从 m a
'feed' a
进入函数 (a -> m b)
并因此得到一个单子值 m b
作为结果。
用我自己的话说:绑定运算符 (>>=)
允许链接 monadic 函数(返回 monadic 值),其中较早函数的输出值是下一个函数的输入。对吗?
回到列表实例。 map f xs
对 xs
中的每个值使用函数 f
。所以 map (*2) [1,2,3]
结果是 [2,4,6]
。这就是我想要的吗?我应该如何在这里使用 concat
?
concat
的定义如下:
concat :: [[a]] -> [a]
为什么我在 (>>=)
函数中得到列表列表?是不是因为 list 是 monad 并且我从该列表中获取每个值以将其提供给 f
而 map
只是获取单例输入?但是我该如何遍历整个列表呢? 'picking each value' 发生在哪里?如果 map
将整个列表 xs 作为输入(这就是我的理解)为什么我应该得到一个列表列表?
如果
x :: [a]
f :: a -> [b]
然后
map f :: [a] -> [[b]]
map f x :: [[b]]
所以,我们需要将后者压扁为[b]
。这是由 concat
.
完成的
请注意 f
是如何生成一个列表的,因此 map
将其变成了列表的列表。这很关键:如果 f
不是生成列表而是 f :: a->b
,那么我们不需要 concat
—— 我们甚至不需要 monad,因为仿函数提供 fmap=map :: (a->b) -> [a] -> [b]
就够了。
monad 相对于 functor 的额外好处主要在于让 f
产生一个 monadic 类型的值。
我在这里发现了一些问题:Redefining monad list instance。我目前正试图让我的头缠绕在单子上。但是我在这里需要一些帮助,我没有将列表的实例定义作为 monad。
这是我给 monad 的列表实例的定义:
instance Monad [] where
xs >>= f = concat $ map f xs
return x = [x]
fail _ = []
我不明白,为什么我需要在绑定函数中使用 concat。
这是我对 (>>=)
:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
所以我有一些 monadic 值 m a
和一个函数,取一个值 a
并产生一个 monadic 值 m b
作为参数。我从 m a
'feed' a
进入函数 (a -> m b)
并因此得到一个单子值 m b
作为结果。
用我自己的话说:绑定运算符 (>>=)
允许链接 monadic 函数(返回 monadic 值),其中较早函数的输出值是下一个函数的输入。对吗?
回到列表实例。 map f xs
对 xs
中的每个值使用函数 f
。所以 map (*2) [1,2,3]
结果是 [2,4,6]
。这就是我想要的吗?我应该如何在这里使用 concat
?
concat
的定义如下:
concat :: [[a]] -> [a]
为什么我在 (>>=)
函数中得到列表列表?是不是因为 list 是 monad 并且我从该列表中获取每个值以将其提供给 f
而 map
只是获取单例输入?但是我该如何遍历整个列表呢? 'picking each value' 发生在哪里?如果 map
将整个列表 xs 作为输入(这就是我的理解)为什么我应该得到一个列表列表?
如果
x :: [a]
f :: a -> [b]
然后
map f :: [a] -> [[b]]
map f x :: [[b]]
所以,我们需要将后者压扁为[b]
。这是由 concat
.
请注意 f
是如何生成一个列表的,因此 map
将其变成了列表的列表。这很关键:如果 f
不是生成列表而是 f :: a->b
,那么我们不需要 concat
—— 我们甚至不需要 monad,因为仿函数提供 fmap=map :: (a->b) -> [a] -> [b]
就够了。
monad 相对于 functor 的额外好处主要在于让 f
产生一个 monadic 类型的值。