ssm*_*ssm 17 monads haskell types typeclass
Haskell的新手,我正试图找出这个Monad的东西.monadic绑定运算符 - >>=具有非常奇特的类型签名:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)
为了简化,我们替换Maybe为m:
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Run Code Online (Sandbox Code Playgroud)
但请注意,该定义可以用三种不同的方式编写:
(>>=) :: Maybe a -> (Maybe a -> Maybe b) -> Maybe b
(>>=) :: Maybe a -> ( a -> Maybe b) -> Maybe b
(>>=) :: Maybe a -> ( a -> b) -> Maybe b
Run Code Online (Sandbox Code Playgroud)
在这三个中,中心的一个是最不对称的.但是,据我所知,如果我们想避免(LYAH称为样板代码),第一个有点无意义.但是,接下来的两个,我更喜欢最后一个.对于Maybe,这看起来像:
当这被定义为:
(>>=) :: Maybe a -> (a -> b) -> Maybe b
instance Monad Maybe where
Nothing >>= f = Nothing
(Just x) >>= f = return $ f x
Run Code Online (Sandbox Code Playgroud)
这里,a -> b是一个普通的功能.此外,我没有立即看到任何不安全的东西,因为在函数应用程序之前Nothing捕获异常,因此除非获得a,否则不会调用该函数.a -> bJust a
那么也许有些事情对我来说并不明显,这导致(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b定义比更简单的(>>=) :: Maybe a -> (a -> b) -> Maybe b定义更受欢迎?是否有一些固有的问题与(我认为是)更简单的定义相关联?
Gab*_*lez 22
如果用下面的派生函数(from Control.Monad)来思考它会更加对称:
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
(f >=> g) x = f x >>= g
Run Code Online (Sandbox Code Playgroud)
这个函数很重要的原因是它遵循三个有用的方程式:
-- Associativity
(f >=> g) >=> h = f >=> (g >=> h)
-- Left identity
return >=> f = f
-- Right identity
f >=> return = f
Run Code Online (Sandbox Code Playgroud)
这些是类别法,如果你翻译它们(>>=)而不是使用(>=>),你会得到三个monad法则:
(m >>= g) >>= h = m >>= \x -> (g x >>= h)
return x >>= f = f x
m >>= return = m
Run Code Online (Sandbox Code Playgroud)
所以它不是(>>=)优雅的运算符,而是(>=>)您正在寻找的对称运算符.然而,我们通常认为的原因(>>=)是因为这是do符号的荒谬.
让我们考虑Maybemonad的一个常见用途:处理错误.说我想安全地划分两个号码.我可以写这个函数:
safeDiv :: Int -> Int -> Maybe Int
safeDiv _ 0 = Nothing
safeDiv n d = n `div` d
Run Code Online (Sandbox Code Playgroud)
然后使用标准Maybemonad,我可以做这样的事情:
foo :: Int -> Int -> Maybe Int
foo a b = do
c <- safeDiv 1000 b
d <- safeDiv a c -- These last two lines could be combined.
return d -- I am not doing so for clarity.
Run Code Online (Sandbox Code Playgroud)
请注意,在每个步骤中,safeDiv都可能失败,但在两个步骤中都safeDiv需要Ints,而不是Maybe Ints.如果>>=有这个签名:
(>>=) :: Maybe a -> (a -> b) -> Maybe b
Run Code Online (Sandbox Code Playgroud)
你可以将函数组合在一起,然后给它一个Nothing或一个Just,或者它将打开它Just,遍历整个管道,并重新包装它Just,或者它只是Nothing通过基本上未触及的.这可能有用,但它不是monad.为了它有用,我们必须能够在中间失败,这就是这个签名给我们的东西:
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Run Code Online (Sandbox Code Playgroud)
顺便说一下,你设计的签名确实存在:
flip fmap :: Maybe a -> (a -> b) -> Maybe b
Run Code Online (Sandbox Code Playgroud)