簡體   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