繁体   English   中英

用`<= <`编写Monadic函数

[英]Composing Monadic Functions with `<=<`

我正在尝试理解<=<函数:

ghci> :t (<=<)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c

据我了解,我给它2个函数和a ,然后我会得到一个mc

那么,为什么这个例子不编译?

import Control.Monad

f :: a -> Maybe a
f = \x -> Just x

g :: a -> [a]
g = \x -> [x]

foo :: Monad m => a -> m c
foo x = f <=< g x

对于foo 3 ,我希望Just 3因此。

但我得到这个错误:

File.hs:10:15:
    Couldn't match expected type `a0 -> Maybe c0'
                with actual type `[a]'
    In the return type of a call of `g'
    Probable cause: `g' is applied to too many arguments
    In the second argument of `(<=<)', namely `g x'
    In the expression: f <=< g x Failed, modules loaded: none.

这里有两个错误。

首先, (<=<)只有在共享同一个monad时才编写monadic函数。 换句话说,你可以用它来组成两个Maybe函数:

(<=<) :: (b -> Maybe c) -> (a -> Maybe b) -> (a -> Maybe c)

......或两个列表功能:

(<=<) :: (b -> [c]) -> (a -> [b]) -> (a -> [c])

...但你不能编写一个列表函数,也许这样就可以了。 这样做的原因是当你有这样的类型签名时:

(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)

...编译器将确保所有m必须匹配。

第二个错误是你忘了为你的作文加上括号。 你可能想要的是这个:

(f <=< g) x

...如果省略括号,编译器会将其解释为:

f <=< (g x)

修复函数的一种简单方法就是定义一个将Maybe s转换为列表的辅助函数:

maybeToList :: Maybe a -> [a]
maybeToList  Nothing = []
maybeToList (Just a) = [a]

这个函数实际上有以下两个很好的属性:

maybeToList . return = return

maybeToList . (f <=< g) = (maybeToList . f) <=< (maybeToList . g)

...如果你将(maybeToList .)视为类似于fmap并将(<=<)视为类似于(.)return类似于id那么这些是(maybeToList .)函数法则。

然后解决方案变为:

(maybeToList . f <=< g) x

请注意,在

(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c

m是静态的 - 你试图在定义中用[]Maybe替换m - 这不会进行类型检查。

您可以使用<=<来组成形式a -> mb函数,其中m单个 monad。 请注意,您可以使用不同的类型参数,但不需要将其约束为多态a

以下是使用此模式约束到列表monad的示例:

f :: Int -> [Int]
f x = [x, x^2]

g :: Int -> [String]
g 0 = []
g x = [show x]

λ> :t g <=< f
g <=< f :: Int -> [String]
λ> g <=< f $ 10
["10","100"]

你不能把monad混合在一起。 当你看到签名

(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c

Monad m只有一个Monad,而不是两个不同的Monad。 如果是,签名就像是

(<=<) :: (Monad m1, Monad m2) => (b -> m2 c) -> (a -> m1 b) -> a -> m2 c

但实际情况并非如此,实际上通常不可能实现。 可以做点什么

f :: Int -> Maybe Int
f 0 = Just 0
f _ = Nothing

g :: Int -> Maybe Int
g x = if even x then Just x else Nothing

h :: Int -> Maybe Int
h = f <=< g

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM