[英]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.