Я изучаю композицию монад. Хотя я уже понимаю, как сочинять, скажем, Async
и Result
как выполнено здесь Я изо всех сил пытаюсь составить Монаду продолжения и Монаду государства.
Начиная с базовой 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 () }
Тогда также есть базовая реализация монады продолжения:
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
Я пытался снять ограничение, но пока не смог сделать это