2013-04-25 27 views
7

Tôi vừa phát hiện ra Racket cách đây vài ngày và tôi đang cố gắng thoải mái hơn bằng cách viết một tập lệnh nhỏ để tạo hình ảnh đại diện cho mã nguồn sử dụng #lang slideshow.Lỗi khi xác định trong Racket

Tôi biết rằng khi lập trình trong một mô hình chức năng, bạn nên tạo hầu như tất cả các biến của mình với let, nhưng tôi thấy rằng nó giới thiệu quá nhiều mức lồng nhau và Racket cho phép có một API quá phức tạp đòi hỏi các dấu ngoặc đơn thừa. Tôi chắc chắn điều này là để loại bỏ sự mơ hồ khi sử dụng let theo những cách mạnh mẽ hơn, nhưng vì mục đích của tôi, nó chỉ là một sự khó chịu. Do đó, tôi đang tạo tất cả các biến của mình với define và viết các khối với begin nếu tôi cần (chẳng hạn như trong phần nội dung của câu lệnh if).

Vấn đề là tôi đã nhiều lần nhận được những gì dường như là lỗi rất bí ẩn. Tôi chắc rằng tôi chỉ đang mắc phải một số sai lầm của người mới bắt đầu ngớ ngẩn, mới làm quen với ngôn ngữ, nhưng tôi thực sự không thể tìm ra nguồn gốc của đơn khiếu nại.

Dưới đây là mã vi phạm:

(define sub-code (foldr ht-append (rectangle 0 0) (map internal-style (rest code)))) 

mặc dù gì chúng tôi đang xác định sub-code để có vẻ khá thích hợp. Nếu tôi thay thế bằng

(define sub-code '()) 

Tôi nhận được lỗi tương tự. DrRacket đang nói rằng define đang được sử dụng trong ngữ cảnh biểu thức. Tôi hiểu những gì lỗi này thường có nghĩa là - IE rằng nó sẽ tăng lên khi bạn viết mã như (print (define x 10)), nhưng tôi không thể nhìn thấy những gì sẽ kích hoạt nó ở đây.

Nếu nó giúp, define đây là lúc bắt đầu của một khối begin, bên trong một tuyên bố if

(if (list? code) 
    (begin 
     (define sub-code '()) 
     ; a few more define statements and finally an expression)) 

Các DrRacket thông báo lỗi cụ thể là in ấn là

define: not allowed in an expression context in: (define sub-code (quote())) 

Tôi nghĩ có lẽ define isn không được phép trong các khối begin nhưng tôi đã kiểm tra the docs và một trong các ví dụ cho begin

(begin 
    (define x 10) 
    x) 

Vì vậy, tôi thực sự không biết phải làm gì. Cảm ơn trước!

Trả lời

9

Định nghĩa được cho phép trong ngữ cảnh 'nội dung', như trong lambdalet trong số những người khác. Các mệnh đề hậu quả và thay thế của if không phải là bối cảnh cơ thể; chúng là ngữ cảnh biểu thức và do đó các định nghĩa không được phép.

begin là đặc biệt - begin trong ngữ cảnh cơ thể cho phép định nghĩa, nhưng begin trong ngữ cảnh diễn đạt các định nghĩa cấm. Trường hợp của bạn rơi vào sau này.

Ví dụ:

(define (foo . args)  #| body context #|) 
(define foo (lambda args #| body context |#)) 
(define (foo . args) 
    (let (...) 
    #| body context |#)) 

từ khóa cú pháp đòi hỏi phải có biểu thức: if, cond, case, and, or, when, unless, do, begin.Kiểm tra cú pháp chính thức trong bất kỳ báo cáo Đề án nào (r {4,5,6,7} rs); tìm kiếm <body>, <sequence>, <command><expression>.

Ngoài ra, nếu bạn cần một bối cảnh cơ thể trong một biểu thức, chỉ quấn một hình thức cú pháp let, như vậy:

(if test 
    (let() 
     (define foo 'foo) 
     (list foo foo)) 
    alternate) 
+1

Cảm ơn! Kết thúc bằng việc chỉ với 'let', nhưng nó rất hữu ích khi biết rằng' bắt đầu' có thể biến dạng hoàn toàn như thế. Trực giác của tôi là '(bắt đầu foo)' sẽ chỉ là viết tắt của '((lambda() foo))', nhưng tôi đoán nó phức tạp hơn thế. – SelectricSimian

6

Như GoZoner giải thích, bạn có thể không sử dụng define trong bối cảnh biểu.

Bạn có thể làm gì thay thế?

Sử dụng let:

(if (list? code) 
    (let ([x '()]) 
     x) 
    ... 

Hoặc nó sẽ làm việc với một "trống rỗng" letdefine:

(if (list? code) 
    (let() 
     (define x '()) 
     x) 
    ... 

Nhưng đó là một chút ngớ ngẩn.

Hoặc sử dụng conddefine:

(cond [(list? code) 
     (define x '()) 
     x] 
     ... 

này cách cuối cùng - sử dụng conddefine - là gần nhất với những gì current Racket style guide khuyến cáo.

+0

'cond' không thiết lập ngữ cảnh biểu thức (theo thử nghiệm của tôi trong R6RS và thông số dự thảo R7RS). – GoZoner

+1

Trong vợt '(cond [#t (xác định x 1) x])' là hợp lệ và trả về '1'. –

+1

Vâng, chúng ta đều biết ... Vợt không phải là Đề án ... :-) Trong Ikarus '(cond (#t (xác định foo 'foo) (danh sách foo foo)))' -> "Lỗi: Một định nghĩa đã được tìm thấy nơi một biểu hiện được mong đợi. " – GoZoner

4

Dưới đây là chi tiết khác, từ tài liệu Racket.

Yêu cầu different contexts vì các macro phải mở rộng khác nhau, tùy thuộc vào biểu mẫu ngôn ngữ nào được phép.

Như những người khác đã nói, định nghĩa không được phép trong ngữ cảnh biểu thức ("expr ..." trong tài liệu), nhưng được chấp nhận trong các ngữ cảnh khác.

Trong các mục nhập tài liệu khác, "nội dung ..." cho biết ngữ cảnh định nghĩa nội bộ (guide, reference), ví dụ: trong cơ thể lambda và "biểu mẫu ..." cho biết tất cả ngữ cảnh không biểu hiện, như trong tài liệu để bắt đầu.

0

Hoặc bạn có thể quấn biểu thức trong (bắt đầu) ví dụ: (bắt đầu (xác định x 10) (xác định y 100) (xác định z 1000))

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