怎样理解Functor与Monad
1. 复合函数操作符
- Prelude> :t (.)
- (.) :: (b -> c) -> (a -> b) -> a -> c
- Prelude> (.) ((+) 5) ((*) 2) 4
- 13
所以(.)操作符的作用,是将4作为参数传递给((*) 2)函数,再将结果传递给((+) 5)函数。
这就是数学里面的复合函数:
f(x) = 2x
g(x) = x + 5
g(f(x)) = g(2x) = (2x) + 5 = 2x + 5
g(f(4)) = 2*4 + 5 = 13
2. Functor
- 194 {- | The 'Functor' class is used for types that can be mapped over.
- 195 Instances of 'Functor' should satisfy the following laws:
- 196
- 197 > fmap id == id
- 198 > fmap (f . g) == fmap f . fmap g
- 199
- 200 The instances of 'Functor' for lists, 'Data.Maybe.Maybe' and 'System.IO.IO'
- 201 satisfy these laws.
- 202 -}
- 203
- 204 class Functor f where
- 205 fmap :: (a -> b) -> f a -> f b
- 206
- 207 -- | Replace all locations in the input with the same value.
- 208 -- The default definition is @'fmap' . 'const'@, but this may be
- 209 -- overridden with a more efficient version.
- 210 (<$) :: a -> f b -> f a
- 211 (<$) = fmap . const
id是一个函数
- Prelude> :t id
- id :: a -> a
- Prelude> id "Daniel"
- "Daniel"
- Prelude> id 1
- 1
- Prelude> id True
- True
- Prelude> id Just "Happy"
- Just "Happy"
- Prelude> id Nothing
- Nothing
Functor是一种typeclass,用来定义一种允许的操作集合,这里是fmap,并且对于fmap提出了需要满足的条件:
- fmap id == id
- fmap (f . g) == fmap f . fmap g
可以视为"交换律"和“分配律”
- Prelude Data.Char> fmap isDigit ((++) ['0'..'9'] ['a'..'f'])
- [True,True,True,True,True,True,True,True,True,True,False,False,False,False,False,False]
- Prelude Data.Char> :t isDigit
- isDigit :: Char -> Bool
fmap不仅可以操作List(此时与List的函数map作用相同),还可以操作比如Maybe
- Prelude Data.Char> fmap isDigit (Just 'a')
- Just False
- Prelude Data.Char> fmap isDigit (Nothing)
- Nothing
- Prelude Data.Char> fmap isDigit (Just '1')
- Just True
3. Manod
Monad与Functor一样,也是用来定义类型可以进行的操作集合。
- Prelude Data.Char> :i Monad
- class Monad m where
- (>>=) :: m a -> (a -> m b) -> m b
- (>>) :: m a -> m b -> m b
- return :: a -> m a
- fail :: String -> m a
- -- Defined in `GHC.Base'
- instance Monad Maybe -- Defined in `Data.Maybe'
- instance Monad (Either e) -- Defined in `Data.Either'
- instance Monad [] -- Defined in `GHC.Base'
- instance Monad IO -- Defined in `GHC.Base'
- instance Monad ((->) r) -- Defined in `GHC.Base'
可以看到,这些操作包括(>>=) (>>) return fail
(>>)执行两个操作,但是放弃前一个操作的结果
- Prelude Data.Char> :t (>>)
- (>>) :: Monad m => m a -> m b -> m b
- Prelude Data.Char> (>>) "Daniel" "King"
- "KingKingKingKingKingKing"
- 212
- 213 {- | The 'Monad' class defines the basic operations over a /monad/,
- 214 a concept from a branch of mathematics known as /category theory/.
- 215 From the perspective of a Haskell programmer, however, it is best to
- 216 think of a monad as an /abstract datatype/ of actions.
- 217 Haskell's @do@ expressions provide a convenient syntax for writing
- 218 monadic expressions.
- 219
- 220 Minimal complete definition: '>>=' and 'return'.
- 221
- 222 Instances of 'Monad' should satisfy the following laws:
- 223
- 224 > return a >>= k == k a
- 225 > m >>= return == m
- 226 > m >>= (\x -> k x >>= h) == (m >>= k) >>= h
- 227
- 228 Instances of both 'Monad' and 'Functor' should additionally satisfy the law:
- 229
- 230 > fmap f xs == xs >>= return . f
- 231
- 232 The instances of 'Monad' for lists, 'Data.Maybe.Maybe' and 'System.IO.IO'
- 233 defined in the "Prelude" satisfy these laws.
- 234 -}
- 235
- 236 class Monad m where
- 237 -- | Sequentially compose two actions, passing any value produced
- 238 -- by the first as an argument to the second.
- 239 (>>=) :: forall a b. m a -> (a -> m b) -> m b
- 240 -- | Sequentially compose two actions, discarding any value produced
- 241 -- by the first, like sequencing operators (such as the semicolon)
- 242 -- in imperative languages.
- 243 (>>) :: forall a b. m a -> m b -> m b
- 244 -- Explicit for-alls so that we know what order to
- 245 -- give type arguments when desugaring
- 246
- 247 -- | Inject a value into the monadic type.
- 248 return :: a -> m a
- 249 -- | Fail with a message. This operation is not part of the
- 250 -- mathematical definition of a monad, but is invoked on pattern-match
- 251 -- failure in a @do@ expression.
- 252 fail :: String -> m a
- 253
- 254 {-# INLINE (>>) #-}
- 255 m >> k = m >>= \_ -> k
- 256 fail s = error s
(>>=)是将前一个操作的结果作为参数传递给后一个操作,但是注意需要使用return将从a到b的正常转换(a -> b)变成(a -> mb),即(a -> ma)(a - b) = (a -> mb)
- Prelude Data.Char> :t return
- return :: Monad m => a -> m a
- Prelude Data.Char> :t (>>=)
- (>>=) :: Monad m => m a -> (a -> m b) -> m b
- Prelude Data.Char> (>>=) (return ((++) "Daniel" "King")) ((:) 'X')
- "XDanielKing"
- Prelude Data.Char> (>>=) (return ((++) "Daniel" "King")) ((++) "Hello ")
- "Hello DanielKing"
所以(>>=)和return是配合使用的,效果很类似于Unix下的管道操作。
Monad的设计想法是允许pure的Haskell可以产生一些side effect,或者说除了自身的值以外,可以保存下一些状态信息。
比如在这里, ((++) "Daniel" "King")的结果就传递给了后面的action,这样就可以用来更新状态信息。
比较明显的应用是在IO以及Exception Handling上面。
如果参考数学中的概念,Monad可以被看作是虚数体系,或者是另外一个维度的类型;
普通的类型与Monad类型之间需要显式地进行转换,
return : 普通类型转换成Monad类型
<-:Monad类型转换成普通类型
IO action都是操作的Monad类型。
- *RecursiveContents Control.Monad Data.Char System.FilePath> :t forM
- forM :: Monad m => [a] -> (a -> m b) -> m [b]
- *RecursiveContents Control.Monad Data.Char System.FilePath> forM "Daniel King" $ \ch -> do return (toUpper ch)
- "DANIEL KING"
怎样理解Functor与Monad的更多相关文章
- 函数编程中functor和monad的形象解释
函数编程中functor和monad的形象解释 函数编程中Functor函子与Monad是比较难理解的概念,本文使用了形象的图片方式解释了这两个概念,容易理解与学习,分别使用Haskell和Swift ...
- 泛函编程(28)-粗俗浅解:Functor, Applicative, Monad
经过了一段时间的泛函编程讨论,始终没能实实在在的明确到底泛函编程有什么区别和特点:我是指在现实编程的情况下所谓的泛函编程到底如何特别.我们已经习惯了传统的行令式编程(imperative progra ...
- Functor and Monad in Swift
I have been trying to teach myself Functional Programming since late 2013. Many of the concepts are ...
- Monad / Functor / Applicative 浅析
前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困 ...
- 重新理解 Monad
对于大多数刚刚入门函数式编程的同学来说,monad(单子.又叫单体)可能是这里面的一道坎.你可能对 map . flatMap 以及 filter 再熟悉不过,可是到了高阶的抽象层次上就又会变得一脸懵 ...
- Functor、Applicative 和 Monad(重要)
Functor.Applicative 和 Monad Posted by 雷纯锋Nov 8th, 2015 10:53 am Functor.Applicative 和 Monad 是函数式编程语言 ...
- 浅释Functor、Applicative与Monad
引言 转入Scala一段时间以来,理解Functor.Applicative和Monad等概念,一直是我感到头疼的部分.虽然读过<Functors, Applicatives, And Mona ...
- Functor、Applicative 和 Monad
Functor.Applicative 和 Monad 是函数式编程语言中三个非常重要的概念,尤其是 Monad. 说明:本文中的主要代码为 Haskell 语言,它是一门纯函数式的编程语言. 一.结 ...
- Scalaz(11)- Monad:你存在的意义
前面提到了scalaz是个函数式编程(FP)工具库.它提供了许多新的数据类型.拓展的标准类型及完整的一套typeclass来支持scala语言的函数式编程模式.我们知道:对于任何类型,我们只需要实现这 ...
随机推荐
- Linux访问一个url
命令一:wget(直接把url的内容下载下来) [root@localhost ~]# wget www.baidu.com--2018-06-16 21:23:49-- http://www.bai ...
- 最小公倍数(lcm与gcd)
J - Worker Avin meets a rich customer today. He will earn 1 million dollars if he can solve a hard p ...
- [暑假集训Day1T1]黑暗城堡
因为D[i]表示i号节点到1号节点的最短路径,所以可以先以1为源点跑一边SPFA,预处理出每个点到1号节点的最短路.之后开始考虑所谓的“最短路径生成树”,在这棵生成树中有以下性质:当fa[i]==no ...
- Warning: session_start(): open(/var/lib/php/session/)
Warning: session_start(): open(/var/lib/php/session/) 今天放置一个新的站点www.96net.com.cn在里面,登陆后台出现这种错,之后再lin ...
- wireshark自动化之tshark命令行
tshark是wireshark安装目录下命令行工具 使用tshark可以通过自动化方式调用wireshark tshark -a duration:30 抓包30秒-w cap.cap 保存为cap ...
- 攻防世界--open-source
1.打开源码 打开源码 #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { ) ...
- XMPP即时通讯协议使用(六)——开发Openfire聊天记录插件
转载地址:http://www.cnblogs.com/hoojo/archive/2013/03/29/openfire_plugin_chatlogs_plugin_.html 开发环境: Sys ...
- redis的hmset乐观锁的实现
1.lua脚本(集成实现了乐观锁,hmset ,expire等) local key=KEYS[1]; local oldVerion=tonumber(ARGV[1]); local seconds ...
- python中字典类型的使用
Python字典类型 字典是一种键值对的集合,键值对之间无序 字典类型的定义 采用{}或者dict()来创建字典对象,键值对之间使用:进行分隔. {<键1>:<值1>, < ...
- RESET - 把一个运行时参数值恢复为缺省值
SYNOPSIS RESET name RESET ALL DESCRIPTION 描述 RESET 将运行时参数恢复为缺省值. RESET 是下面语句的一个变种 SET parameter TO D ...