第十三章:應用函子
作為函子的子類型別,應用函子概括了某些函子的額外特性:把函子裡的函式作用到函子裡的值。
1.函子的侷限
函子抽象提供了fmap函式,用來把普通函式升格成可以操作函子容器的函式。例如我們可以把所有能出來a型別的函式升格成處理 Maybe a型別的函式
現假設有一個a->b->c型別的函式,我們可以繼續使用fmap。通過構造replicateB這個函式,使得fmap replicateB的型別變成了Maybe Int->Maybe String
a :: Maybe Int a = Just 3 b :: Char b = 'x' replicate :: Int -> b -> [b] replicateB :: Int -> String replicateB = \x -> replicate x b fmap replicateB a -- Just "xxx"
而實際遇到的問題往往是,參與計算的引數裡不只有一個是包裹在函子型別裡面的。如上面的例子中Char型別的值也包裹在Maybe裡呢?
--模式匹配 replicateMaybe :: Maybe Int -> Maybe a -> Maybe [a] replicateMaybe (Just n) (Just a) = Just $ replicate n a replicateMaybe _ Nothing = Nothing replicateMaybe Nothing _ = Nothing --升格雙引數函式的高階函式liftMaybe2 liftMaybe2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c liftMaybe2 f (Just x) (Just y) = Just $ f x y liftMaybe2 _ _ _ = Nothing
同理可以得到liftMayben,但是這麼做需要為每一種引數數量的情況寫一個特例且無法使用別的型別的函子
一個觀察——如果多引數函式只經過fmap的升格,並部分應用一個包裹在函子中的值,將會得到一個包裹在函子中的函式
replicate :: Int -> a -> [a] replicate :: Int -> (a -> [a]) fmap replicate :: f Int -> f (a -> [a]) fmap replicate (Just 3) :: Maybe (a -> [a])
於是
replicateThreeF :: Maybe (a -> [a]) replicateThreeF = fmap replicate (Just 3) applyMaybe :: Maybe (a -> b) -> Maybe a -> Maybe b applyMaybe (Just f) (Just x) = Just $ f x applyMaybe _ _ = Nothing applyMaybe replicateThreeF (Just 'x') -- Just "xxx" --升格任意引數數量的函式到Maybe引數型別 addAll :: Int -> Int -> Int -> Int addAll x y z = x + y + z (fmap addAll $ Just 1) `applyMaybe` Just 2 `applyMaybe` Just 3
我們可否抽象出一個適用於任意型別函子f上的函式呢?
(<*>) :: Functor f => f (a -> b) -> f a -> f b (<*>) = ???
+對於列表
(<*>) :: [(a -> b)] -> [a] -> [b] fs <*> xs = concat $ map (\f -> map f xs) fs --concat把列表裡的所有列表連線起來 concat :: [[a]] -> [a] concat xss = foldl (++) [] xss
+上面的問題答案是不可以
(<*>) :: Const a (b -> c) -> Const a b -> Const a c cf <*> cx = ???
2.什麼是函子
我們把剛剛希望被抽象出來的、能夠提供<*>定義的函子稱為 應用函子 applicative functor
Applicative 型別代表的就是這一型別
class Functor f => Applicative f where pure :: a -> f a <*> :: f (a -> b) -> f a -> f b
+pure接收一個引數並把它包裹到函子裡。我們把這個升格值的過程叫**調價最小上下文**minimum context +<*>是升格計算的核心——函子應用運算子
+pure和<*>必須滿足四個條件:單位律,組合律,同態律和互換律
Reader應用函子 (->) a
pure :: x -> (a -> x) (<*>) :: (a -> (x -> y)) -> (a -> x) -> (a -> y) instance Applicative ((->) a) where pure x = \_ -> x --pure = const (<*>) :: (a -> (x -> y)) -> (a -> x) -> (a -> y) fxy <*> fx = \a -> fxy a $ fx a
+這個函子常用在配置模組化的問題上
-自然升格
自然升格指的是使用應用函子構建運算的一種書寫習慣
<$>函式是fmap的中綴版本。和$不同的是,<$>是一個左結合的函式,在自然升格裡的作用是把一個函式先升格至函子的範疇,然後就可以方便的使用<*>去繼續應用計算
(<$>) :: (a -> b) -> f a -> f b f <$> x = fmap f x -- <$> = fmap infixl 4 <$>
編譯器自動根據引數型別推匯出了我們需要的應用函子型別,形如
... <$> ... <*> ... <*> ...
這種寫法就叫自然升格
模組Data.Functor中,提供了自然升格寫法中需要的兩個中綴函式 <$ 和 $>
有時,我們希望直接使用某個包裹在函子的值填充到生成的函子中
- Control.Applicative中 的* > 和<*
- 引數從1到3的常用升格函式 liftA, liftA2, liftA3
3.IO應用函子
IO應用函子包裹的是和系統輸入/輸出相關的值
它的作用就是保證和外界的互動
相關文章
- 第十四章:單位半群和一些有趣的應用函子
- 第十三章 模組和包
- Git應用詳解第十講:Git子庫:submodule與subtreeGit
- 第十三章 上傳檔案
- 第十三章 瀏覽器事件瀏覽器事件
- Linux網路管理員手冊(13) 第十三章 電子郵件 (轉)Linux
- 13-第十三章 日期物件Date物件
- 第十三章 sqlplus命令(一)SQL
- 第十三章 sqlplus命令(二)SQL
- 第十三章 瀏覽器事件(bjsuo)瀏覽器事件JS
- 利用鉤子函式來捕捉鍵盤響應的windows應用程式函式Windows
- 函數語言程式設計 - 酷炫Applicative(應用函子) [Swift描述]函數程式設計APPSwift
- 從零開始學Python:第十課-函式和字串的應用Python函式字串
- [單刷APUE系列]第十三章——守護程式
- 第十三章 物件的複製及儲存物件
- 第十三章 Perl的物件導向程式設計物件程式設計
- Flask教程第十三章:國際化和本地化Flask
- 第三章 CSS的應用補充(轉)
- Hash函式及其應用函式
- 第六十三章 Caché 函式大全 $SORTEND 函式函式
- JS高階程式設計第十三章.個人學習筆記JS程式設計筆記
- 第十三章——法律法規與標準化知識(2分)
- gethostbyname函式和getservbyname函式的應用函式
- 第三章 初識vLookup函式函式
- Generator函式非同步應用函式非同步
- 函式計算——應用初探函式
- 函式進階應用3函式
- 鳥哥的Linux私房菜基礎篇 第十三章 shell scriptsLinux
- 函式柯里化和偏函式應用函式
- 理解 Vue 的 setup 應用程式鉤子Vue
- 子函式呼叫函式
- 海口基於區塊鏈為企業提供電子保函應用系統服務區塊鏈
- Knockout應用開發指南第三章:繫結語法(1)
- 第三章 函式與程式結構函式
- Render函式在Vue多頁面應用中的應用函式Vue
- Vue函式式元件的應用Vue函式元件
- javascript高階函式的應用JavaScript函式
- 高階函式應用--currying函式