1. 程式人生 > >Haskell的WriterMonad解構

Haskell的WriterMonad解構

問題匯出

move i = do
    x <- left i
    tell "Go"
    y <- left x
    return y

其中

left i = writer ( x -1,"move left\t')
:t tell "G0" :: MonadWriter [Char] m => m ()

問題

tell "Go"的上下文到底在哪裡

我們一步步的解開

move  :: Int -> Writer String Int
move i = do
    x <- left' i
    _ <- tell "GO\t"
return x

我們把do展開

move i = let
            ok p = do
                    tell "go"
                    return p
            ok _ = fail ".."
           in writer ((i-1),"Move Left\t") >>= ok

展開tell

move' i = let
            ok p = do
                    writer ((),"Go\t")
                    return
p ok _ = fail ".." in writer ((i-1),"Move Left\t") >>= ok

let解構轉換為where解構,暫時消除掉i

move i = writer ((i-1),"Move Left\t") >>= ok where
            ok p = do
                    writer ((),"Go\t")
                    return p

消除掉第二個do

move i = writer ((i-1),"Move Left\t"
) >>= ok where ok p = writer ((),"Go\t") >> return p

增加輔助函式,做最終轉換

instance (Monoid w) => Monad (Writer w) where
    return x = Writer (x,mempty)
    (Writer (x,v)) >>= f = let (Writer ( y,v')) = fx
        in Writer (y, v `mappend` v')
temp ::Int -> Writer String Int
temp i = writer ((),"GO\t") >> return (i-1)

move i =  case runWriter(temp i) of
           (y,v') -> writer (y, "Move Left\t" `mappend` v')
           _ -> writer(0,mempty)

對於temp的模擬,可以參看monad這裡的對於>>的實現,確實是使用了>>=。這樣既滿足了需要序列運算上下文,又能保證丟棄了上文的M a的a,但是仍然可以把M傳遞給下文。而恰好,Writer的宣告形式是Writer String a,這樣可以把a丟棄掉,而把String傳遞給下文,達到了tell要求的僅保留String內容,而忽略a的內容.
結論:
可以看出,上下文首先是因為做了內部的do運算,得到的關鍵的Writer((),"Go")
之後把(i-1) 附屬到了tell的結果上,然後再做外部運算,結束掉x <- left i

相關推薦

學習es6之(變量的賦值)

返回 blog 成了 所在 asc 對象 expected 正弦 peer 數組的解構賦值 ES6允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構。 以前,為變量賦值,只能直接指定值。 let a = 1; let b = 2; let c = 3;

es6 變量的賦值

.com pre syntax data defined math對象 b+ syn 內容 一、數組的解構賦值 數組解構賦值,索引很重要,即順序很重要 1、解構[1,2,3] //把1,2,3分別賦值給a,b,c var [a,b,c]=[1,2

委托、事件--我對他們本質的理解

remove 類型 實例化 如果 方法 擴展 調用 所有 csharp 一、委托 1、因為委托是一個特殊的類,所以定義委托和定義類一樣,可以在命名空間下定義; namespace _06委托的理解 { public delegate void MyDelege

Es6 新增賦值

等價 gin let 一個 函數返回 部分 syntax 解析器 求值 1.數組的解構賦值 基本用法 ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構(Destructuring)。 要想實現解構,就必須是容器,或者具有可遍歷的接口。 以

es6 淺

fin 阮一峰 doc -s 等價 itl under 變量 基本 先上一段代碼, { function move({x: t = 0, y = 0, z = 3} = ‘111‘) { return [x="x",t, y, 9, z]; }

學習es6_

ava rip des 格式 undefined 變量 java 報錯 bsp ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構(Destructuring)。 let [foo, [[bar], baz]] = [1, [[2], 3]];

ECMAscript6新特性之賦值

註意 對象 指定 iterator 接口 模式匹配 我們 結構 pan   在以前,我們要對變量賦值,只能直接指定值。比如:var a = 1;var b = 2;但是發現這種寫法寫起來有點麻煩,一點都不簡潔,而在ECMAScript6中引入了一種新的概念,那就是“解構”,

ES6新特性:賦值(上)

變量賦值 什麽 模式 註意 只需要 一個數 html 代碼 內容 1:什麽是解構賦值 按照一貫的套路,接下來的內容是解釋:什麽是解構賦值? 來看看官方的解釋: ES6允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構(

《深入理解ES6》之

nbsp span 對象 code true 上下文 div 嵌套對象 賦值 結構是一種打破數據解構,將其拆分為更小部分的過程。 對象解構   對象字面量的語法形式是在一個賦值操作符左邊放置一個對象字面量。 let node={ type:"indefi

ES6變量的賦值

def 對象 ons aov aaa let es6 define 等號 // -------------------------------------------------------------------/** * 基本概念: * 本質上就是一種匹配模式,只

ES6賦值

所有 含義 提取 處理 s函數 事情 數據結構 無法 defined 前面的話   我們經常定義許多對象和數組,然後有組織地從中提取相關的信息片段。在ES6中添加了可以簡化這種任務的新特性:解構。解構是一種打破數據結構,將其拆分為更小部分的過程。本文將詳細介紹ES6解構賦值

Python封裝及

解構 python封裝及解構Python的封裝與其他語言的封裝箱不同,python中沒有裝箱的概念,一切皆對象將多個值使用逗號進行分割,本質上是返回元組In [1]: a = 1,2 In [2]: type(a)Out[2]: tuple In [3]: aOut[3]: (1, 2) 封裝在進行交換的時候

ES6學習筆記二 新的聲明方式和變量的賦值!

是什麽 一句話 數組 name ont 簡單 cee 問題 二次 新的聲明方式 在ES5的時候,我們只有一個聲明方式,var!但是在es6中,聲明進行了擴展,我們加上ES5的var的申明方式,我們有了三種聲明方式: var:它是variable的簡寫,可以理解成變量的意思

函數參數

div 集合 提取 位置 urn 關鍵字參數 關鍵字 函數參數 pre 函數參數解構; 給函數提供實參的時候,可以在集合類型前使用*/** 把集合類型的解構解開,提取所有元素作為函數的實參 非字典類型使用*解構成位置參數 字典類型使用**解構成關鍵字參數 提

python函數之參數、參數

函數函數 python函數組成: 定義語句,函數名,參數列表,代碼塊 函數作用: 將一段功能代碼封裝起來,便於復用. 代碼更加簡潔. 函數的分類: 內建函數: 如,max()等 庫函數: 如,math.c

ES6學習之變量的賦值

iter 內部使用 位置 fine 嚴格 true red 組成 個數 1.數組的解構賦值 let [a, b, c] = ["hello", 1, 2] console.log(a) //hello console.log(b) //1 console.log(c) /

賦值--數組的賦值

屬於 多個 提前 就是 yield 等號 個數 code 需要 什麽是解構賦值?ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構(Destructuring)。我的理解是:允許聲明一種模式(數組、對象等),裏面包含一個或多個變量,再分別對這些變量

ES6 變量用法

輸出 ole family 解構 bbb pre turn func status 1、數組解構,可以設置默認值 ‘use strict‘; let [x, y = ‘b‘] = [‘a‘]; //控制臺輸出b console.log(y); 2、對

es6--賦值-用途

set post new fun json val con blog 默認值 // 1:交換變量的值 let a = 1; let b = 2; console.log(a,b); [a,b] = [b,a]; console.log(a,b) // 2:函數返回多個值

【01】數組的賦值

height -a post fine 數組 const 嚴格 如果 寫法 【01】數組的解構賦值魔芋總結:用法1:var [a,b,c]=[1,2,3];用法2:(可以嵌套數組)let [foo, [[bar], baz]] = [1, [[2], 3]];foo //