2010-04-07 86 views
9

我剛剛把我的頭圍繞monads(至少我想我認爲我),更具體地說是國家monad,有些人更聰明,然後我想通了,所以我可能與這個問題。State Monad,爲什麼不是元組?

反正狀態單子通常與A M實施<「一>作爲像這樣(F#):

type State<'a, 'state> = State of ('state -> 'a * 'state) 

現在我的問題:是否有任何理由,爲什麼你不能使用一個元組這裏?除此之外,MonadA<'a, 'b>MonadB<'a, 'b>之間可能存在的不確定性,它們都會成爲等效的('a * 'b)元組。

編輯:新增例如爲清楚起見

type StateMonad() = 
    member m.Return a = (fun s -> a, s) 
    member m.Bind(x, f) = (fun s -> let a, s_ = x s in f a s_) 

let state = new StateMonad() 
let getState = (fun s -> s, s) 
let setState s = (fun _ ->(), s) 
let execute m s = m s |> fst 
+0

問題是什麼?在哪裏使用元組?函數的返回類型是一個元組。 – Brian 2010-04-07 20:39:37

+0

不使用元組而不是狀態類型,只返回一個函數而不是狀態。 – thr 2010-04-07 20:45:53

回答

12

國家單子基本上與類型'state -> 'res * 'state,它代表了計算,需要一些初始狀態併產生結果(與狀態的新值一起)的工作原理。

如果你問我們是否給這個類型一些特殊的名字(例如State<'state, 'res>),那麼答案是無關緊要的。爲該類型提供一些特殊名稱的唯一目的是它使代碼更具可讀性。例如,讓我們來看看下面的例子中的兩個可能的類型簽名:

let foo n = state { 
    let! m = getState() 
    do! setState(m + 1) 
    return sprintf "Result: %d" (n * m) } 

// Using State<'state, 'res> type: 
val foo : int -> State<int, string> 

// Using the underlying representation: 
val foo : int -> int -> int * state 

第一種類型的簽名更清楚地說,我們在一些單子寫功能。第二個例子只是一個函數,需要兩個值int。我認爲第一個的主要好處是你可以更容易地意識到該類型可以用於其他一元計算(使用state { ... }編寫)。

但是,正如我已經指出的那樣,這不是技術要求。人們可能使用這種風格,因爲很多單子都來自哈斯克爾,其中單子與(如State<'state, 'res>),而不是一個計算建設者(如state)相關聯,因此這聽起來像一個好主意,定義Haskell中每個monad的新類型。

+0

謝謝,是的,我根本不打算使用元組版本,我只是在IRC(## fsharp @ freenode)上討論它,我們都沒有看到州類型的技術原因。 – thr 2010-04-08 08:55:13

5

啊,是的,如果問題是:我應該使用一個單一的標籤識別聯合攜帶類型T的數據值,或者我應該只是使用T,那麼你也可以使用。因爲Haskell do語法推斷基於值類型的monad類型(元組表示可能是最多隻有一個Monad的實例)。在Haskell中,您需要使用帶有monad的數據標記,因爲Haskell do語法推斷了基於值類型的monad類型(元組表示可能是最多一個Monad的實例)。而在F#中,計算表達式對於單子類型是明確的(例如state { ... }async { ... }或其他),所以這個限制不是必需的,相同的表示類型可以用於多個單子。

6

類型在您的例子中,一元價值的不只是一個元組 - 這是一個函數返回元組:

'state -> 'res * 'state 

如果你問你是否可以只使用'state * 'res爲一體的類型一元計算,那麼答案是否定的。這是行不通的,因爲沒有辦法(安全地)執行返回操作,它必須具有以下類型的簽名:

// how would we get a value of type 'state in the implementation? 
val return : 'a -> 'state * 'a