[Haskell] State Monad

1. 类型

类型用来区分内存中对程序员来说不同种类的数据块
而内存中存储的是表达式的值
所以,区分内存块的类型,就是区分表达式的类型

静态类型,指的是在编译时就能确定表达式的类型
动态类型,指的是在运行时才能确定表达式的类型

注:
静态类型,也可以说,通过代码文本就能确定表达式的类型

强类型和弱类型是相对而言的
类型系统的强度指的是,在多大程度上能把表达式看做是合法类型的
类型强度的表现形式是,是否允许隐式类型转换
弱类型,更允许隐式类型转换
强类型,更不允许隐式类型转换

2. 定义类型

Haskell中定义类型的方式有以下几种

(1)使用type定义类型别名

type MyTuple = (Int, String)

定义MyTuple为元组类型(Int, String)的别名

(2)使用data定义新类型

data BookType = BookValue Int String

其中,BookType是类型名,又称为类型构造器,BookValue称为值构造器

一个BookType类型值,可以这样定义

let bookValue = BookValue 12 "ab"

注:
因为类型构造器和值构造器会在不同上下文中使用,所以经常把它们写为同一个名字

data Book = Book Int String

遇到名字Book时要小心区分

(3)使用newtype为已有类型定义新的标识
newtype定义的类型,只能有一个值构造器,且值构造器只能有一个字段

例如:
一个值构造器,值构造器只有一个字段,可以

newtype Okay = ExactlyOne Int

类型构造器有多个参数,但是只有一个值构造器,值构造器只有一个字段,也可以

newtype Param a b = Param (Either a b)

字段访问器语法,可以

newtype Record = Record {
    getInt :: Int
}

注:
字段访问器语法,同时定义了字段的类型Int,以及字段的访问器函数getInt :: Record -> Int
例如:
通过值构造器Record构造该类型的值,Record 12
通过访问器提取字段的值,getInt (Record 12)

有一个值构造器,但是值构造器没有字段,不可以

newtype TooFew = TooFew

有一个值构造器,但是值构造器有两个字段,不可以

newtype TooManyFields = Fields Int Int

有多个值构造器,不可以

newtype TooManyCtors = Bad Int
    | Worse Int

3. 带参数的类型

类型构造器也可以带参数

data Maybe a = Nothing
   | Just a

data Either a b = Left a
    | Right b

其中,Maybe是类型构造器,Maybe Int才是一个具体的类型
Either是类型构造器,Either Int String才是一个具体的类型

注:
与函数的Currying相似,类型构造器也可以Currying
Either是一个类型构造器,提供两个类型IntString,得到类型Either Int String
Either Int也是一个类型构造器,提供类型String,得到类型Either Int String

4. newtype

使用newtype为已有类型定义编译时的新标识,
这个标识在运行时会转换为原有的类型,可以称为去壳

例如:
定义新的类型

data DataInt = D Int
    deriving (Eq, Ord, Show)

定义编译时的类型外壳

newtype NewtypeInt = N Int
    deriving (Eq, Ord, Show)

运行时,求值undefined会发生错误

ghci> undefined
*** Exception: Prelude.undefined

运行时,_可以匹配所有,undefined不求值

ghci> case D undefined of D _ -> 1
1

运行时,N外壳会去掉,即case undefined of _ -> 1_可以匹配所有,undefined不求值

ghci> case N undefined of N _ -> 1
1

运行时,D _来匹配undefined的求值结果,undefined要求值,发生错误

ghci> case undefined of D _ -> 1
*** Exception: Prelude.undefined

运行时,N外壳会去掉,即case undefined of _ -> 1_可以匹配所有,undefined不求值

ghci> case undefined of N _ -> 1
1

5. typeclass

类型类提取了相似的运算
类型类的实例是一个类型构造器,这个类型构造器构造的类型具有类型类指定的运算

注:
类型类的实例,是一个类型构造器
类型构造器,可以是零元类型构造器(具体的类型),也可以带参数

例如:

class BasicEq a where
    isEqual :: a -> a -> Bool

其中,BasicEq类型类,定义了isEqual函数

指定类型构造器Bool(零元类型构造器,即具体的类型)是BasicEq类型类的实例
于是,isEqual就具体化为isEqual :: Bool -> Bool -> Bool

instance BasicEq Bool where
    isEqual True  True  = True
    isEqual False False = True
    isEqual _     _     = False

6. Monad

Monad是一个类型类
针对一般化的链式操作,它定义了>>=return两种运算

class Monad m where
    -- chain
    (>>=)  :: m a -> (a -> m b) -> m b
    -- inject
    return :: a -> m a

其中,Monad类型类的实例,是一个单参类型构造器

注:
m a类型的值,通常称之为action
有时候,返回action的函数,也称之为action

instance Monad Maybe where
    Nothing >>= f = Nothing
    Just a >>= f = f a
    return = Just

其中,>>=具体化为了(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
return具体化为了return :: a -> Maybe a
f的类型是f :: a -> Maybe b
NothingJustMaybe a类型的值构造器

data Maybe a = Nothing
    | Just a

注:
Monad还定义了两种操作>>fail

(>>) :: m a -> m b -> m b
a >> f = a >>= \_ -> f

>>并不关心a的执行结果,只是进行顺序调用

fail :: String -> m a
fail = error

7. do语法块

do语法块会在编译时转换为>>=>>return形式

(1)单个action

doNotation1 =
    do act

translated1 =
    act

(2)多个action

doNotation2 =
    do act1
       act2
       {- ... etc. -}
       actN

translated2 =
    act1 >>
    do act2
       {- ... etc. -}
       actN

finalTranslation2 =
    act1 >>
    act2 >>
    {- ... etc. -}
    actN

(3)带有<-的action

doNotation3 =
    do pattern <- act1
       act2
       {- ... etc. -}
       actN

translated3 =
    let f pattern = do act2
                       {- ... etc. -}
                       actN
        f _ = fail "..."
    in act1 >>= f

(4)let

doNotation4 =
    do let val1 = expr1
           val2 = expr2
           {- ... etc. -}
           valN = exprN
       act1
       act2
       {- ... etc. -}
       actN

translated4 =
    let val1 = expr1
        val2 = expr2
        valN = exprN
    in do act1
          act2
          {- ... etc. -}
          actN

8. State Monad

为原有类型定义一个新的标识

newtype State s a = State {
        runState :: s -> (a, s)
    }

其中,类型构造器是State
字段的类型是s->(a,s)是一个函数
字段访问器是runState

注:
因为State是一个双参类型构造器,
所以State s是一个单参类型构造器
runState的类型是runState :: State s a -> s -> (a, s)

指定State s是Monad类型类的实例

instance Monad (State s) where
...

注:
Monad类型类的实例,是一个单参类型构造器,
所以,State s是Monad类型类的实例,State不是

returnState :: a -> State s a
returnState a = State $ \s -> (a, s)

bindState :: State s a -> (a -> State s b) -> State s b
bindState m k = State $ \s -> let (a, s') = runState m s
                                                    in runState (k a) s'

其中,m的类型是m :: State s a
k的类型是k :: a -> State s b
runState的类型是runState :: State s a -> s -> (a, s)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 初识状态 先看一个小游戏,这个小游戏用字符串来控制,最后得到总分。c用来启动和停止计分,在启动计分状态下a加一分,...
    何幻阅读 1,003评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 本文为翻译,个人学习之用,原地址 程序状态 如果你以前有其他语言的编程经验,你可能写过一些函数或者方法来控制程序的...
    ParkinWu阅读 3,012评论 0 3
  • 前言 近期又开始折腾起Haskell,掉进这个深坑恐怕很难再爬上来了。在不断深入了解Haskell的各种概念以及使...
    Tangentw阅读 2,134评论 0 9
  • 骄阳如火 残暴的炙烤着大地 闷热的天 压抑的让人透不过气来 独坐窗前 思绪万千 一路走来 肩上的行囊空空如...
    不在彼岸只在海阅读 217评论 2 2