【发布时间】:2019-06-06 18:29:29
【问题描述】:
我正在研究单子组合。虽然我已经知道如何编写 Async 和 Result 就像执行 here 一样,但我正在努力编写 Continuation Monad 和 State Monad。
从基本的State Monad 实现和用于测试目的的State-based-Stack 开始:
type State<'State,'Value> = State of ('State -> 'Value * 'State)
module State =
let runS (State f) state = f state
let returnS x =
let run state =
x, state
State run
let bindS f xS =
let run state =
let x, newState = runS xS state
runS (f x) newState
State run
let getS =
let run state = state, state
State run
let putS newState =
let run _ = (), newState
State run
type StateBuilder()=
member __.Return(x) = returnS x
member __.Bind(xS,f) = bindS f xS
let state = new StateBuilder()
module Stack =
open State
type Stack<'a> = Stack of 'a list
let popStack (Stack contents) =
match contents with
| [] -> failwith "Stack underflow"
| head::tail ->
head, (Stack tail)
let pushStack newTop (Stack contents) =
Stack (newTop::contents)
let emptyStack = Stack []
let getValue stackM =
runS stackM emptyStack |> fst
let pop() = state {
let! stack = getS
let top, remainingStack = popStack stack
do! putS remainingStack
return top }
let push newTop = state {
let! stack = getS
let newStack = pushStack newTop stack
do! putS newStack
return () }
然后还有一个 Continuation Monad 的基本实现:
type Cont<'T,'r> = (('T -> 'r) -> 'r)
module Continuation =
let returnCont x = (fun k -> k x)
let bindCont f m = (fun k -> m (fun a -> f a k))
let delayCont f = (fun k -> f () k)
let runCont (c:Cont<_,_>) cont = c cont
let callcc (f: ('T -> Cont<'b,'r>) -> Cont<'T,'r>) : Cont<'T,'r> =
fun cont -> runCont (f (fun a -> (fun _ -> cont a))) cont
type ContinuationBuilder() =
member __.Return(x) = returnCont x
member __.ReturnFrom(x) = x
member __.Bind(m,f) = bindCont f m
member __.Delay(f) = delayCont f
member this.Zero () = this.Return ()
let cont = new ContinuationBuilder()
我正在尝试像这样编写它:
module StateK =
open Continuation
let runSK (State f) state = cont { return f state }
let returnSK x = x |> State.returnS |> returnCont
let bindSK f xSK = cont {
let! xS = xSK
return (State.bindS f xS) }
let getSK k =
let run state = state, state
State run |> k
let putSK newState = cont {
let run _ = (), newState
return State run }
type StateContinuationBuilder() =
member __.Return(x) = returnSK x
member __.ReturnFrom(x) = x
member __.Bind(m,f) = bindSK f m
member this.Zero () = this.Return ()
let stateK = new StateContinuationBuilder()
虽然这可以编译并且看起来是正确的(就机械跟随步骤组合而言)我无法实现StateK-based-Stack。
到目前为止我有这个,但这是完全错误的:
module StackCont =
open StateK
type Stack<'a> = Stack of 'a list
let popStack (Stack contents) = stateK {
match contents with
| [] -> return failwith "Stack underflow"
| head::tail ->
return head, (Stack tail) }
let pushStack newTop (Stack contents) = stateK {
return Stack (newTop::contents) }
let emptyStack = Stack []
let getValue stackM = stateK {
return runSK stackM emptyStack |> fst }
let pop() = stateK {
let! stack = getSK
let! top, remainingStack = popStack stack
do! putSK remainingStack
return top }
let push newTop = stateK {
let! stack = getSK
let! newStack = pushStack newTop stack
do! putSK newStack
return () }
一些帮助理解为什么以及如何是非常受欢迎的。 如果有一些你可以指出的阅读材料,它也可以工作。
********* 在AMieres 评论后编辑**************
新的bindSK 实现试图保持签名正确。
type StateK<'State,'Value,'r> = Cont<State<'State,'Value>,'r>
module StateK =
let returnSK x : StateK<'s,'a,'r> = x |> State.returnS |> Continuation.returnCont
let bindSK (f : 'a -> StateK<'s,'b,'r>)
(m : StateK<'s,'a,'r>) : StateK<'s,'b,'r> =
(fun cont ->
m (fun (State xS) ->
let run state =
let x, newState = xS state
(f x) (fun (State k) -> k newState)
cont (State run)))
尽管如此,'r 类型已被限制为 'b * 's
我试图删除约束,但我还没有能够做到这一点
【问题讨论】:
-
我可以告诉你
bindSK是不正确的。f的类型应该是:'a -> Cont<State<'s,'b>,'r>,但实际上是:'a -> State<'s,'b> -
感谢@AMieres,我再次执行了我的实现,现在看来我有一个不需要的约束。
'r已被限制为'b*'s -
你确定有可能吗?在我看来,这是自相矛盾的。由于最后一个延续是唯一能够运行状态单子的延续,并且由于状态值决定了延续。怎样才能提前确定合适的续作?
-
我认为是,状态应该在每个延续中运行。我将阅读有关该主题的更多信息并再试一次
-
@AMieres 我提出了一个可行的实现,请参阅下面的答案。你怎么看?
标签: functional-programming f# monads continuations state-monad