2010-05-30 6 views
5
[<ReflectedDefinition>] 
let rec x = (fun() -> x + "abc")() 

재귀 값이 위의 다음과 같은 F # 컴파일러 오류가 발생하여 샘플 코드 :F # quotations 버그입니까?

error FS0432: [<ReflectedDefinition>] terms cannot contain uses of the prefix splice operator '%'

내가 위의 코드에있는 슬라이스 연산자 사용을 볼 수는 ... :) 버그처럼 보이는 이 ReflectedDefinitionAttribute를 통해 인용에 문제가있는 것처럼

만, 일반 인용이 잘 작동 보이는 :

let quotation = 
    <@ let rec x = (fun() -> x + "abc")() in x @> 

숨겨진 Lazy.createLazy.force 용도와 예상되는 결과를 생성 :

val quotation : Quotations.Expr<string> = 
    LetRecursive 
    ([(x, Lambda (unitVar, 
     Application 
     (Lambda (unitVar0, 
      Call (None, 
      String op_Addition[String,String,String](String, String), 
      [Call (None, 
       String Force[String](Lazy`1[System.String]), // ` 
       [x]), Value ("abc")])), 
     Value (<null>)))), 
    (x, Call (None, Lazy`1[String] Create[String](FSharpFunc`2[Unit,String]), [x])), 
    (x, Call (None, String Force[String](Lazy`1[String]), [x]))], x) // ` 

그래서 질문이이 F # 컴파일러의 버그인지?

답변

5

나는 이것이 F #에서 재귀 값을 처리 할 때 발생할 수 있다고 생각합니다. 당신이 바로 순환 참조를 생성하고 있기 때문에,

[<ReflectedDefinition>] 
let foo x = (fun() -> x + "abc")() 

// To construct the recursive value, you'd write: 
let rec x = foo x 

마지막 줄은 물론 (당신의 원본 코드와 같은) 유효하다, 그러나 주어야한다 : 해결 방법으로, 당신은 매개 변수로 재귀 참조를 설정할 수 있습니다 당신 생각은 - 실제로는 λ39 함수에 x을 넣을 수 있습니다.


편집원래, 나는 문제가 다음과 같이 될 수 있다고 생각하지만, 나는 (주석 참조) 지금은 잘 모르겠어요.

예기치 않은 버그보다 나에게 (아마도 알려진) 제한이 더 비슷해 보입니다. 첫 번째 경우에는 x이라는 공용 값 (.NET에서 볼 수 있음)을 바인딩하는 반면, 두 번째 경우에는 x이라는 이름의 코드는 두 버전의 코드 사이에 중요한 차이가 있습니다. 인용.

과 같을 것이다 어셈블리의 메타 데이터에 저장되어야 할 것이다 인용 :

let rec x = <@ (fun() -> %x + "abc")() @> 
몸이 인용

하지만 할 필요가 있으므로 x는 인용 기호 아니다 (즉, 평가되고 그 결과가 그 자리에서 사용될 것입니다). 직접 참조가있는 재귀 값 - x을 정의의 일부로 평가해야하므로이 코드는 실패합니다. 따라서이 코드는 작동하지 않습니다.

그러나, 나는 몇 가지 런타임 측면을 포함하기 때문에 %ReflectedDefinition 인용 (즉, 당신이 메타 데이터 위를 저장할 수 없다)에 나타나지 않을 수 있다고 생각 - 메타 데이터를로드 할 때 x을 평가해야 할 것 .

+0

답변 해 주셔서 감사합니다. 토마스! 메타 데이터가 '<@ (fun() -> % x + "abc")() @>'처럼 보이는'[]'버전을 쓰고있는 것에 동의하지 않습니다. 인용문 안의'x' 이름은 인용문 슬라이스가 아닌 public .NET 값에 바인딩되어야합니다! 만약 당신이 말한 것처럼 행동한다면,'[] let rec() = (fun() -> f() + "abc")()'같은 expecption을 만들어야한다. 그러나 그렇지 않습니다. – ControlFlow

+0

@ControlFlow : 귀하의 요점이 맞다고 생각합니다. 어쩌면 이것은 F #에서 일반적으로 매우 복잡한 것 인 재귀 적 값으로 무언가를해야만합니다. –

+0

필자도 그렇게 생각합니다. F #과 같은 열망한 언어에서는 재귀 값을 다루는 것이 쉽지 않을 것입니다. 컴파일러는 [] 사용법을 이와 같이 제한해야합니다. – ControlFlow