ST Monad

首先在这里请允许我斗胆说一说Monad,这个概念在函数式编程流行的今天,已经在编程的过程中出现的越来越多,不过老实说,接下来的和Monad可能没啥关系,但是ST Monad确实是很实用的东西。

问题背景

在函数式编程中有一个问题相信一直困扰着像我一样的初学者,那就是函数式要求函数是纯函数,甚至有些语言还需要函数是Total的,也就是说一个函数同样的输出,必须有一个确定的输入(deterministic)。这一点可以增加程序分析工具,形式化工具的可用性,能够更加好的保证代码正确。但是这和一个我们在编程中必须要遇到的东西: 变量矛盾了,为什么?

int a = 0;
int adda (int b) {
    // do something
    a = a + b;
    // do something
    return a;
}
print (adda(1));
print (adda(1));

这里adda的输出对于相同的输入根本没法保持一致。
当然这种情况我们完全是可以避免的,因为这里的问题本质在于,我们允许了全局变量。函数内更新了外面的东西。当然这不是说这样我们对整个程序就没有办法验证分析程序正确性了,如果我们引入霍尔逻辑,即给出前后条件的方式其实还是可以继续讨论的。
但是很多时候,全局变量是完全没有必要的,完全可以通过值传递等方式取完成,我们在命令式编程里的很多做法其实是在逻辑上浪费了,比如上面的程序,传a进函数就可以了。

int adda (int a, int b) {
    // do something
    int c = a + b;
    // do something
    return c;
}
print (adda(0, 1));

print (adda(adda(0, 1), 1));

In Haskell

在haskell中表达带有顺序结构的函数当然是完全没有问题的,do block就可以。

adda a b= do 
    -- something
    let c = a + b 
    -- something
    return c

main = do
    print (adda (adda 0 1) 1)

ok , so far so good.
但是如果adda这个函数更加复杂,在函数内部也要对c进行改变呢?比如我们在一个循环中会对c做操作。

int adda (int b) {
    // do something
    c = a + b;
    // do something
   for(int i=0; i < 10; i++) {
       // do something
       c++;
   } 
    return a;
}

这时候haskell还想完全不使用变量,但是又想用顺序结构去完成就非常麻烦了。。。。。即使使用了函数式的写法,你也会不得不使用各种嵌套的递归,更加糟糕的情况是因为使用递归,大量的中间变量c会产生,这会增加gc的负担。

但是我们如果仔细思考一下,增加内部变量c真的会影响我们函数式编程纯的影响吗?
似乎并不会,最外面的adda这个函数的输入输出依然是确定的,从外面看,我们依然是safe的。而haskell也确实提供了这样一种折衷的思路, ST Monad,看个简单求和的例子吧

import Control.Monad.ST
import Data.STRef
import Control.Monad


sumST :: Num a => [a] -> a
sumST xs = runST $ do           -- runST takes out stateful code and makes it pure again.

    n <- newSTRef 0             -- Create an STRef (place in memory to store values)

    forM_ xs $ \x -> do         -- For each element of xs ..
        modifySTRef n (+x)      -- add it to what we have in n.

    readSTRef n                 -- read the value of n, and return it.

例子来自haskell wiki.
在runST包裹的do block中使用newSTRef,我们就可以得到一个变量啦,起码看起来是个真正的变量。

ST Monad其实也没有很神秘,他和书上常见的那种状态的表示,偏射没什么区别,只是他读状态很像IO,众所周知,IO是带魔法的不纯状态包裹(doc里直接称为deeply magical),通过一个converter, ST 被映射到IO上了,所以这里的变量操作最终是使用类似IO的方式实现。

有了变量,很多原地算法就可以实现了~

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