Haskell 学习笔记 -- functor / applicative
这部分肯定是 Haskell 中最最抽象的了,我上课就没懂(
还有什么范畴论,自闭了
Functor 函子
函子的意思是一类容器,它里面可以装各种东西
比如 [] \ Maybe \ Tree
要让一个数据结构成为 Functor , 必须支持函数 fmap
1 instance Functor [] where
2 --fmap :: ( a -> b ) -> f a - f b
3 fmap g [] = []
4 fmap g (x:xs) = fmap g xs ++ [g x]
fmap 相当于把函数作用到数据结构的每一个位置上
Applicative
多个参数的fmap(
很抽象举例子
fmap0 :: a -> f a
fmap1 :: a -> b -> f a -> f b
fmap2 :: a -> b -> c -> f a -> f b -> f c
applicative 需要实现两个函数:
pure :: a -> f a
(<*>) :: f ( a -> b ) -> f a -> f b
-- <*> 是左结合的
然后就可以改写了
fmap2 g x y = pure g <*> x <*> y
对于Maybe / [] / IO 来说
instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
g :: a -> b mx :: f a
(Just g ) <*> mx = fmap g mx
instance Applicative [] where
pure x = [x]
gs <*> xs = [g x | g <- gs , x <- xs ]
-- pure (*) <*> [1,2] <*> [3,4]
-- [3,4,6,8]
instance Applicative IO where
pure = return
mg <*> mx = do {g <- mg; x <- mx; return (g x)}
IO 的一个具体例子
getChars :: Int -> IO String
getChats 0 = return []
--(:) :: a -> [a] -> [a]
--pure (:) -> IO (a -> [a] -> [a] )
getChars n = pure (:) <*> getChar <*> getChars (n-1)
Effective progframming
有效的编程(x
看来我以前的都是无效的
这里有效可能更像“有副作用”
比如说 Maybe 可能失败(Nothing)
[] 可能有多种解
IO 附带输入输出
所以我们也可以用 applicative 改装函数
标准库中有一个函数:sequenceA 用于一个序列里头装函子 出来的是函子里头装序列
(这里的函子是有副作用的,见上,所以可以将函子也理解为作用
Evaluate each action in the structure from left to right, and collect the results.
sequenceA :: Applicative f => [f a] -> f [a]
sequenceA (x:xs) = pure (:) <*> x <*> sequenceA xs
pure (:) :: f ( a -> [a] -> [a] )
getChars :: Int -> IO string
getChars n = sequenceA (replicate n getChar )
-- getChar :: IO char
-- replicate :: Int -> a -> [a]
--replicate n getChar :: [IO char]
最后补充一种等价写法:
pure g <*> x1
g <$> x1
fmap g x1
三者等价