我只是试图获得monad,所以如果我问一个糟糕的问题请耐心等待,但是...
如果monad只需要:
(a -> M a)
,其中M是monadic类型构造函数,(M a -> (a -> M b) -> M b)
,这是绑定操作(我理解为将monad映射到非monadic到monadic值函数)......并不意味着:
(M a -> a)
和(M (M a) -> M a)
不是含蓄要求的吗?不会这通常会导致问题吗?
假设我们有一组函数S,它们都具有类型(x -> y)
,其中x和y是任意类型。
现在,假设我使用一组monadic函数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可以忽略不计(例如伐木monad)。
另外,没有展平的分层单子怎么办?我理解列表可以看作monad,其中限制扁平化是一个明确而合理的选择,但是async (async a)
monadic值的假设情况呢async
没有扁平函数?绑定只意味着一层" 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之间是否存在真正的区别?
答案 0 :(得分:1)
不会这通常会导致问题吗?
你可能会说这是"设计"。其中一种可能的用途是IO
;一旦你有一个被IO
污染的价值,你必须"冒泡&#34 ;;你无法隐藏函数在纯值下执行IO的事实。
这并不意味着我要么必须手动转换每个(a - > b) - > (a - > M b)通过在某处应用monadic构造函数?
这比你想象的要容易,因为每个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)
并非隐式要求
那个是假的。你只需要bind来实现它。
join :: (Monad m) => m (m a) -> m a
join x = x >>= id