monad 不保证 layered/non-layered monadic 值对 non-layered/non-monadic 函数的适用性,这是 good/bad 的事情吗?
Do monads not guarantee the applicability of layered/non-layered monadic values to non-layered/non-monadic functions, and is this a good/bad thing?
我只是想得到 monad,如果我问的问题不好,请多多包涵,但是...
如果单子只需要:
(a -> M a)
,其中 M 是单子类型构造函数,
(M a -> (a -> M b) -> M b)
,这是绑定操作(我理解为将 monad 映射到非 monadic 到 monadic 值函数)
...这不是说:
(M a -> a)
和
(M (M a) -> M a)
不是隐式要求的吗?
这通常不会引起问题吗?
假设我们有一组函数 S,它们的类型都是 (x -> y)
,其中 x 和 y 是任意类型。
现在,假设我使用一组单子函数 M 进行编程,它们的类型是 x -> M y
.
这不是说一旦我把一个类型变成了M y
,我就不能使用任何(x -> y)
的功能了吗? 或者,我可以假设我可以(M x -> (x -> y) -> (y -> M y) -> M y)
吗?
再者,我们平时编程的时候不就是要提取原始类型吗?在某些东西之间切换时,比如 async a -> a
或 maybe a -> a
... 这不是一个常见的操作吗?我绝对可以看到有人想要优化 monad 的情况,如果他们认为它可以忽略不计(例如,日志记录 monad)。
另外,没有扁平化的分层单子呢?我知道列表可以被视为单子,其中限制扁平化是一个明确且合乎逻辑的选择,但是 async (async a)
单子值的假设情况又如何呢? async
没有扁平化功能? bind是不是只隐含了一层"monadic reduction",我们经常可以假设(M a -> (a -> M a) -> M a)
经常可以看成是(M a -> (M a -> a) -> (a -> M a) -> M a)
,而(M M a -> (a -> M a) -> M a or M M a)
不一定行得通?展平和非展平 monad 之间真的有区别吗?
Won't this usually cause a problem?
你可能会说这是"by design"。一种可能的用途是 IO
;一旦你的值被 IO
污染,你就必须 "bubble up";您无法隐藏一个函数在纯值下执行 IO 的事实。
wouldn't that mean I either have to manually convert each (a -> b) -> (a -> M b) by applying a monadic constructor somewhere?
这比你想象的要容易,因为每个 Monad 也是一个 Functor 和一个 Applicative Functor:
randomDice :: IO Int
randomDice = randomRIO (1,6)
cheat :: Int -> Int
cheat = (+1)
main = do
dice <- randomDice
dice' <- cheat <$> randomDice
拥有所有 fmap
、<$>
、liftA/liftM
和 pure/return
机制,这使得在 monadic 中轻松使用纯函数变得非常简单上下文。
(M (M a) -> M a)
is not implicitly required
那个是假的。你只需要绑定即可实现它。
join :: (Monad m) => m (m a) -> m a
join x = x >>= id
我只是想得到 monad,如果我问的问题不好,请多多包涵,但是...
如果单子只需要:
(a -> M a)
,其中 M 是单子类型构造函数,(M a -> (a -> M b) -> M b)
,这是绑定操作(我理解为将 monad 映射到非 monadic 到 monadic 值函数)
...这不是说:
(M a -> a)
和(M (M a) -> M a)
不是隐式要求的吗?
这通常不会引起问题吗?
假设我们有一组函数 S,它们的类型都是
(x -> y)
,其中 x 和 y 是任意类型。现在,假设我使用一组单子函数 M 进行编程,它们的类型是
x -> M y
.
这不是说一旦我把一个类型变成了M y
,我就不能使用任何(x -> y)
的功能了吗? 或者,我可以假设我可以(M x -> (x -> y) -> (y -> M y) -> M y)
吗?
再者,我们平时编程的时候不就是要提取原始类型吗?在某些东西之间切换时,比如 async a -> a
或 maybe a -> a
... 这不是一个常见的操作吗?我绝对可以看到有人想要优化 monad 的情况,如果他们认为它可以忽略不计(例如,日志记录 monad)。
另外,没有扁平化的分层单子呢?我知道列表可以被视为单子,其中限制扁平化是一个明确且合乎逻辑的选择,但是 async (async a)
单子值的假设情况又如何呢? async
没有扁平化功能? bind是不是只隐含了一层"monadic reduction",我们经常可以假设(M a -> (a -> M a) -> M a)
经常可以看成是(M a -> (M a -> a) -> (a -> M a) -> M a)
,而(M M a -> (a -> M a) -> M a or M M a)
不一定行得通?展平和非展平 monad 之间真的有区别吗?
Won't this usually cause a problem?
你可能会说这是"by design"。一种可能的用途是 IO
;一旦你的值被 IO
污染,你就必须 "bubble up";您无法隐藏一个函数在纯值下执行 IO 的事实。
wouldn't that mean I either have to manually convert each (a -> b) -> (a -> M b) by applying a monadic constructor somewhere?
这比你想象的要容易,因为每个 Monad 也是一个 Functor 和一个 Applicative Functor:
randomDice :: IO Int
randomDice = randomRIO (1,6)
cheat :: Int -> Int
cheat = (+1)
main = do
dice <- randomDice
dice' <- cheat <$> randomDice
拥有所有 fmap
、<$>
、liftA/liftM
和 pure/return
机制,这使得在 monadic 中轻松使用纯函数变得非常简单上下文。
(M (M a) -> M a)
is not implicitly required
那个是假的。你只需要绑定即可实现它。
join :: (Monad m) => m (m a) -> m a
join x = x >>= id