2014-01-27 2 views
4

이 질문은 영감을 얻었습니다 this question. 예제 (ListBuilder)를 이해했지만 상태 모나드에 대해 while 루프를 만들지 못했습니다. 나에게 명확하지 않은 것은 bind의 몸체 인 while 루프의 몸체가 반복되는 과정을 반복하는 것입니다.상태 모나드 - While- 루프

감사합니다.

///////////////////////////////////////////////////////////////////////////////////// 
// Definition of the state 
///////////////////////////////////////////////////////////////////////////////////// 
type StateFunc<'State, 'T> = 'State -> 'T * 'State 



///////////////////////////////////////////////////////////////////////////////////// 
// Definition of the State monad 
///////////////////////////////////////////////////////////////////////////////////// 
type StateMonadBuilder<'State>() = 

    // M<'T> -> M<'T> 
    member b.ReturnFrom a : StateFunc<'State, 'T> = a 

    // 'T -> M<'T> 
    member b.Return a : StateFunc<'State, 'T> = (fun s -> a, s) 

    // M<'T> * ('T -> M<'U>) -> M<'U> 
    member b.Bind(p : StateFunc<_, 'T>, rest : 'T -> StateFunc<_,_>) : StateFunc<'State, 'U> = 
     (fun s -> 
      let a, s' = p s 
      rest a s') 

    member b.Zero() = fun s ->(), s 

    member b.Delay f = f 

    member b.Run f = f() 

    // Getter for the whole state, this type signature is because it passes along the state & returns the state 
    member b.getState : StateFunc<'State, _> = (fun s -> s, s) 

    // Setter for the state 
    member b.putState (s:'State) : StateFunc<'State, _> = (fun _ ->(), s) 

    // (unit -> bool) * M<'T> -> M<'T> 
    member b.While (cond, body: StateFunc<'State, _>): StateFunc<'State, _> = 
     (fun s -> 
      if cond() then 
       let bind = 
        let _, s' = body s 
        fun s' -> body s'  
       b.While (cond, bind) // This is wrong 
      else 
       body s) 
+1

예제 코드는 [ExtCore] (https://github.com/jack- 파파/ExtCore). 'StateBuilder' 타입의'While' 멤버에 대한 정의가 포함되어 있는지보기 위해 코드를 보셨습니까? –

+0

굉장합니다. https://github.com/jack-pappas/ExtCore/blob/master/ExtCore/Control.fs에서 하나를 찾았습니다. 고맙습니다. – NoIdeaHowToFixThis

답변

4

당신이 ExtCore에서 서로 다른 계산 빌더를 보면,주의해야 할 하나 개의 흥미로운 것은이 - 어떤 모나드를 들어, While (도 For) 멤버의 구현은 일반적으로 동일합니다.

항상 작업을 Bind, ZeroWhile의 재귀 적 용도로 표현할 수 있기 때문입니다. 당신이 모나드와 함께 작업하는 경우 따라서, 당신은 항상이 같은 (그냥 모나드와 M<_> 교체)를 정의한다 : 이것은 모든 계산에 대한 사실이 아니다

// (unit -> bool) * M<'T> -> M<'T> 
member this.While (guard, body : M<_>) : M<_> = 
    if guard() then 
     this.Bind (body, (fun() -> this.While (guard, body))) 
    else 
     this.Zero() 

을 - 계산은 어떤 식 으로든 더 흥미로운 경우 , While의 다른 구현이 필요할 수도 있지만 위의 설명은 적절한 기본값입니다.

제외 - F #에서 사용자 지정 계산식을 정의해야한다는 요구 사항은 매우 드뭅니다. 예를 들어, 관용적 인 F # 코드는 거의 예를 들어 모나드를 거의 사용하지 않습니다. Haskell과 대부분의 경우, 표준 라이브러리 (ExtCore가 정의한 것, 더 고급 기능을 수행하는 경우)가 무엇인지 잘 알고 있어야합니다. 아마도 사용자 지정 계산이 필요하지만 잘못된 방향으로 이끌 기가 산만해질 수 있습니다 ...