2014-04-17 5 views
4

this question에 대한 후속 질문입니다.이 계산 표현식 빌더가 for for 루프에서 "unit"을 기대하는 이유는 무엇입니까?

사용자 지정 작업을 통해 값을 누적하는 계산 식 작성기를 만들고 동시에 표준 F # 언어 구문을 지원하려고합니다. 간단한 예를 들어 설명하기 위해 F # 목록을 작성하는 계산식을 사용하고 있습니다. kvb와 Daniel의 제안 덕분에 더 나아 갔지만 여전히 for 루프에 문제가 있습니다.

빌더 :

type Items<'a> = Items of 'a list 

type ListBuilder() = 
    member x.Yield(vars) = Items [], vars 
    member x.Run(l,_) = l 
    member x.Zero() = Items [],() 
    member x.Delay f = f() 
    member x.ReturnFrom f = f 

    member x.Combine((Items curLeft, _), (Items curRight, vars)) = 
     (Items (curLeft @ curRight), vars) 

    member x.Bind(m: Items<'a> * 'v, f: 'v -> Items<'a> * 'o) : Items<'a> * 'o = 
     let (Items current, vals) = m 
     x.Combine(m, f vals) 

    member x.While(guard, body) = 
     if not (guard()) then 
      x.Zero() 
     else 
      x.Bind(body, fun() -> x.While(guard, body)) 

    member x.TryWith(body, handler) = 
     try 
      x.ReturnFrom(body()) 
     with e -> 
      handler e 

    member x.TryFinally(body, compensation) = 
     try 
      x.ReturnFrom(body()) 
     finally 
      compensation() 

    member x.Using(disposable:#System.IDisposable, body) = 
     let body' = fun() -> body disposable 
     x.TryFinally(body', fun() -> 
      match disposable with 
      | null ->() 
      | disp -> disp.Dispose()) 

    member x.For(xs:seq<'a>, body) = 
     x.Using(xs.GetEnumerator(), fun enum -> 
      x.While(enum.MoveNext, x.Delay(fun() -> body enum.Current))) 

    [<CustomOperation("add", MaintainsVariableSpace=true)>] 
    member x.Add((Items current, vars), [<ProjectionParameter>] f) = 
     Items (current @ [f vars]), vars 

    [<CustomOperation("addMany", MaintainsVariableSpace=true)>] 
    member x.AddMany((Items current, vars), [<ProjectionParameter>] f) = 
     Items (current @ f vars), vars 


let listBuilder = ListBuilder() 

let build (Items items) = items 

이 버전은 같은 내가 전에 할 수 없었던 일, 수 있습니다 :

let stuff = 
    listBuilder { 
     let x = 5 * 47 
     printfn "hey" 
     add x 
     addMany [x .. x + 10] 
    } |> build 

는 그러나, 나는 아직이 일에 컴파일러 오류를 받고 있어요 :

let stuff2 = 
    listBuilder { 
     for x in 1 .. 50 do 
      add x    
    } |> build 

이 경우 IDE는 x에 for x in의 밑줄을 표시하고 "이 식 유형 단위가있을 것으로 예상되었지만 유형은 int입니다. "

루프 변수가 유형 단위 일 것으로 예상되는 이유는 분명하지 않습니다. 분명히 나는 ​​어딘가에 잘못된 메소드 서명을 가지고있다. 나는 필자가 있어야하는 모든 곳에서 누적 된 상태를 넘지 않을 것이라고 생각한다. 그러나 컴파일러 오류는 내가 잘못 된 부분을 좁히는 데 도움이되지 않는다. 모든 제안을 부탁드립니다.

답변

3

즉각적인 원인은 While 함수가 body 유형을 제한한다는 것입니다. 그러나 일반적으로 동일한 연산 식에서 사용자 지정 연산과 제어 흐름 연산자를 모두 사용할 수 없으므로 서명을 수정하더라도 원하는 작업을 수행 할 수 있다고는 생각지 않습니다.

+0

좋아, 그럼 내가 제어 흐름 연산자와 사용자 지정 작업을 혼합하는 데 많은 어려움을 겪고있는 이유를 설명합니다. 컬렉션을 처리하기 위해 몇 가지 추가 사용자 지정 연산자를 추가 할 것입니다. 즉, 루프 부족은 너무 많은 문제가되지 않을 것입니다. 감사. –