2013-04-25 23 views
7

Właśnie odkryłem Racket kilka dni temu i staram się go bardziej komfortowo napisać mały skrypt generujący obrazy do reprezentowania kodu źródłowego przy użyciu #lang slideshow.Błąd z definiowaniem w Rakiecie

Wiem, że podczas programowania w paradygmacie funkcjonalnym dobrą praktyką jest tworzenie prawie wszystkich zmiennych za pomocą let, ale uważam, że wprowadza zbyt wiele poziomów zagnieżdżania, a let Racket ma zawikłany interfejs API, który wymaga zbędnych nawiasów. Jestem pewien, że to ma na celu usunięcie niejednoznaczności podczas korzystania z let w bardziej potężny sposób, ale dla moich celów jest to po prostu irytacja. Dlatego tworzę wszystkie zmienne z define i piszę bloki z begin, jeśli muszę (np. W treści instrukcji if).

Problem polega na tym, że wielokrotnie otrzymywałem bardzo tajemnicze błędy. Jestem pewien, że właśnie popełniłem błąd głupiego początkującego, będąc nowym językiem, ale naprawdę nie mogę znaleźć źródła skargi.

Oto kod naruszającym przepisy:

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

chociaż co mamy do definiowania sub-code Wygląda całkiem nieistotne. Jeśli wymienię go na

(define sub-code '()) 

Otrzymuję ten sam błąd. DrRacket mówi, że define jest używany w kontekście wyrażenia. Rozumiem, co ten błąd miałby normalnie oznaczać - IE, który podnosiłby, gdy piszesz kod taki jak (print (define x 10)), ale nie widzę, co by go tutaj wyzwoliło.

Jeśli to pomoże, to define jest na początku begin bloku, wewnątrz instrukcji if

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

konkretnym komunikatem o błędzie DrRacket drukowania jest

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

Myślałem, że może define ISN 't dozwolone w blokach begin, ale sprawdziłem the docs i jeden z przykładów dla begin jest

(begin 
    (define x 10) 
    x) 

Tak naprawdę nie wiem co robić. Z góry dziękuję!

Odpowiedz

9

Definicje są dozwolone w kontekście "ciała", np. W lambda i let. Następujące i alternatywne klauzule if nie są kontekstami ciała; są to konteksty ekspresji, dlatego definicje nie są dozwolone.

jest wyjątkowy - begin w kontekście treści umożliwia definicje, ale begin w kontekstach wyrażeń nie zezwala na definicje. Twoja sprawa przypada na później.

Na przykład:

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

składniowe słowa kluczowe, które wymaga wyrażenia: if, cond, case, and, or, when, unless, do, begin.Zapoznaj się z formalną składnią w dowolnym raporcie Scheme (r {4,5,6,7} rs); poszukaj <body>, <sequence>, i <expression>.

Ponadto, jeśli trzeba kontekst ciała w wyrażeniu, po prostu zawinąć let składniową formy, takie jak:

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

Dzięki! Skończyło się na używaniu 'let', ale przydaje się wiedza, że' begin' może tak automatycznie przekształcać. Moja intuicja polegała na tym, że '(begin foo)' będzie skrótem dla '((lambda() foo))', ale myślę, że to jest bardziej skomplikowane. – SelectricSimian

6

Jak wyjaśniono GoZoner, nie można używać define w kontekście wypowiedzi.

Co można zamiast tego zrobić?

Zastosowanie let:

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

Albo będzie pracować z "pustym" letidefine:

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

ale to trochę głupie.

Albo użyć cond i define:

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

Ten ostatni sposób - za pomocą cond i define - jest najbliżej, co current Racket style guide zaleca.

+0

'cond' nie ustanawia kontekstu wyrażenia (zgodnie z moim testem w R6RS i specyfikacji roboczej R7RS). – GoZoner

+1

W Racket '(cond [#t (zdefiniuj x 1) x])' jest poprawny i zwraca '1'. –

+1

Cóż, wszyscy wiemy ... Rakieta nie jest Schematem ... :-) W Ikarus '(cond (#t (define foo 'foo) (list foo foo)))' -> "Błąd: Znaleziono definicję gdzie oczekiwano wyrażenia ". – GoZoner

4

Oto więcej szczegółów, od dokumentów Racket.

Wymagane są different contexts, ponieważ makra muszą rozszerzać się w różny sposób, w zależności od dozwolonych form języka.

Jak powiedzieli inni, definicje nie są dozwolone w kontekstach wyrażeń ("expr ..." w dokumentach), ale są dobrze w innych kontekstach.

W innych pozycjach dokumentu "body ..." wskazuje kontekst wewnętrznej definicji (guide, reference), na przykład w ciałach lambda, a "formularz ..." wskazuje wszystkie konteksty bezwyrażeń, jak w przypadku dokumenty na początek.

0

Albo można owinąć wyrażenia w (begin) np (zaczynają (define x 10) (określić pręd 100) (1000) definiują oo)