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的更多相关文章

  1. 函数编程中functor和monad的形象解释

    函数编程中functor和monad的形象解释 函数编程中Functor函子与Monad是比较难理解的概念,本文使用了形象的图片方式解释了这两个概念,容易理解与学习,分别使用Haskell和Swift ...

  2. 泛函编程(28)-粗俗浅解:Functor, Applicative, Monad

    经过了一段时间的泛函编程讨论,始终没能实实在在的明确到底泛函编程有什么区别和特点:我是指在现实编程的情况下所谓的泛函编程到底如何特别.我们已经习惯了传统的行令式编程(imperative progra ...

  3. Functor and Monad in Swift

    I have been trying to teach myself Functional Programming since late 2013. Many of the concepts are ...

  4. Monad / Functor / Applicative 浅析

    前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困 ...

  5. 重新理解 Monad

    对于大多数刚刚入门函数式编程的同学来说,monad(单子.又叫单体)可能是这里面的一道坎.你可能对 map . flatMap 以及 filter 再熟悉不过,可是到了高阶的抽象层次上就又会变得一脸懵 ...

  6. Functor、Applicative 和 Monad(重要)

    Functor.Applicative 和 Monad Posted by 雷纯锋Nov 8th, 2015 10:53 am Functor.Applicative 和 Monad 是函数式编程语言 ...

  7. 浅释Functor、Applicative与Monad

    引言 转入Scala一段时间以来,理解Functor.Applicative和Monad等概念,一直是我感到头疼的部分.虽然读过<Functors, Applicatives, And Mona ...

  8. Functor、Applicative 和 Monad

    Functor.Applicative 和 Monad 是函数式编程语言中三个非常重要的概念,尤其是 Monad. 说明:本文中的主要代码为 Haskell 语言,它是一门纯函数式的编程语言. 一.结 ...

  9. Scalaz(11)- Monad:你存在的意义

    前面提到了scalaz是个函数式编程(FP)工具库.它提供了许多新的数据类型.拓展的标准类型及完整的一套typeclass来支持scala语言的函数式编程模式.我们知道:对于任何类型,我们只需要实现这 ...

随机推荐

  1. 前端webpack & vue

    地址 : https://blog.csdn.net/jiang7701037

  2. 厉害了,Google大神每天写多少行代码?

    文章转自开源中国社区,编译自:Quora Quora上有个有趣的问题:Google工程师们每天写多少行代码? Google 的 AdMob 全栈工程师 Raymond Farias 在 Quora 发 ...

  3. [Codeforces 1178D]Prime Graph (思维+数学)

    Codeforces 1178D (思维+数学) 题面 给出正整数n(不一定是质数),构造一个边数为质数的无向连通图(无自环重边),且图的每个节点的度数为质数 分析 我们先构造一个环,每个点的度数都是 ...

  4. 创建一个java项目并部署到weblogic服务器

    转自:https://blog.csdn.net/krystal_sl/article/details/52847953 新建一个项目的步骤 打开eclipse,右键点击new–>java pr ...

  5. 系统INIT 启动脚本的结构/etc/rc.d/init.d/*

  6. CentOS下安装中文man 手册

    为了方便使用man,安装中文手册,具体如下: 版本:CentOS release 6.6 (Final) 中文包:http://pkgs.fedoraproject.org/repo/pkgs/man ...

  7. Swoole 简单学习(2)

    Swoole 简单学习(2) swoole之tcp服务器: //创建tcp服务器new swoole_server(string $host,int $port,int $mode=SWOOLE_PR ...

  8. 太可怕了!黑客是如何攻击劫持安卓用户的DNS?

    最近发现的针对Android设备的广泛路由器的DNS劫持恶意软件现在已升级为针对iOS设备以及桌面用户的功能. 被称为RoamingMantis的恶意软件最初发现在上个月劫持了互联网路由器,以散布旨在 ...

  9. Debian取消从光盘安装软件的方式(please insert the disc labeled)

    与Ubuntu不同,使用apt-get install packages时Debian可能会提示: Media change: please insert the disc labeled 'Debi ...

  10. hdu 5964:平行四边形 【计算几何】

    打重现赛时,一点思路也没有,然后又看到这题AC数那么少,就直接放弃了.今天重新看了看,借鉴了下别人的,发现此题应该算是一道可解题. 看上去,这题的ans是同时有两个点作为自变量的函数(然而n^2复杂度 ...