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

Các mẫu mã với giá trị đệ quy trên sản xuất F # trình biên dịch báo lỗi sau:Đây có phải là lỗi báo giá F # không?

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

Tôi không thể nhìn thấy bất kỳ việc sử dụng toán tử cắt trong đoạn mã trên, trông giống như một lỗi ... :)

Hình như đây là vấn đề với báo giá qua ReflectedDefinitionAttribute chỉ, báo giá bình thường hoạt động tốt:

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

sản xuất kết quả dự kiến ​​với ẩn Lazy.createLazy.force tập quán:

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) // ` 

Vì vậy, câu hỏi là: đây là một F # biên dịch lỗi hay không?

Trả lời

5

Tôi nghĩ rằng điều này có thể do điều trị các giá trị đệ quy trong F #. Là một khắc phục, bạn có thể biến tham chiếu đệ quy vào một tham số:

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

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

Dòng cuối cùng là tất nhiên không hợp lệ (giống như mã ban đầu của bạn), bởi vì bạn đang tạo một tham chiếu đệ quy ngay lập tức, nhưng nó sẽ cho bạn ý tưởng - trong thực tế, bạn có thể gửi kèm theo x trong một hàm lambda.


EDITBan đầu, tôi nghĩ rằng vấn đề có thể như dưới đây, nhưng tôi không chắc chắn bây giờ (xem ý kiến).

Dường như một giới hạn (có thể đã biết) đối với tôi hơn là lỗi không mong muốn. Có một sự khác biệt quan trọng giữa hai phiên bản của mã bạn đã viết - trong trường hợp đầu tiên, bạn đang ràng buộc giá trị công khai (hiển thị với .NET) có tên là x trong trường hợp thứ hai, x chỉ là một biểu tượng chỉ được sử dụng trong bảng báo giá.

Đoạn trích dẫn rằng sẽ phải được lưu trữ trong các siêu dữ liệu của hội đồng sẽ trông như thế này:

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

Cơ thể được trích dẫn, nhưng x không phải là một biểu tượng được trích dẫn, vì vậy nó cần phải được nối vào báo giá (nghĩa là, nó sẽ được đánh giá và kết quả sẽ được sử dụng tại vị trí của nó). Lưu ý rằng mã này sẽ thất bại, bởi vì bạn đang khai báo một giá trị đệ quy với tham chiếu ngay lập tức - x cần được đánh giá như là một phần của định nghĩa của nó, vì vậy điều này sẽ không hoạt động.

Tuy nhiên, tôi nghĩ rằng % không thể xuất hiện trong ReflectedDefinition trích dẫn (có nghĩa là, bạn không thể lưu trữ trên trong meta-data), bởi vì nó liên quan đến một số khía cạnh thời gian chạy - bạn cần phải đánh giá x khi tải meta-data .

+0

Cảm ơn câu trả lời của bạn, Tomas! Tôi không đồng ý với bạn rằng khi tôi đang viết phiên bản '[]' mà siêu dữ liệu sẽ trông giống như '<@ (fun() ->% x + "abc")() @> '. Bên trong ngoặc kép, tên 'x' phải được ràng buộc với giá trị .NET công khai, không phải là dấu ngoặc kép! Nếu nó hoạt động giống như bạn nói, đoạn mã như thế này: '[] cho phép rec f() = (fun() -> f() +" abc ")()' cũng nên tạo ra cùng một sự giải thích, nhưng không. – ControlFlow

+0

@ControlFlow: Tôi nghĩ rằng điểm của bạn có ý nghĩa. Có lẽ điều này đã làm một cái gì đó với các giá trị đệ quy mà nói chung là điều khá phức tạp trong F #. –

+0

Tôi nghĩ như vậy quá, xử lý các giá trị đệ quy là nhiệm vụ không tầm thường đối với các ngôn ngữ háo hức như F # ... Có lẽ trình biên dịch chỉ nên hạn chế [] tập quán như thế này. – ControlFlow

Các vấn đề liên quan