2010-04-07 47 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