2013-04-25 26 views
7

Ich habe gerade Racket vor ein paar Tagen entdeckt, und ich versuche, es bequemer zu bekommen, indem ich ein kleines Skript schreibe, das Bilder erzeugt, um den Quellcode mit #lang slideshow darzustellen.Fehler beim Definieren im Racket

Ich weiß, dass es bei der Programmierung in einem funktionalen Paradigma praktisch ist, fast alle Variablen mit let zu erstellen, aber ich finde, dass es zu viele Verschachtelungsebenen einführt und dass Racket's eine überkomplizierte API hat, die überflüssige Klammern benötigt. Ich bin mir sicher, dass dies die Mehrdeutigkeit bei der Verwendung von let auf leistungsfähigere Weise zu entfernen, aber für meine Zwecke ist es nur ein Ärgernis. Folglich erstelle ich alle meine Variablen mit 10 und schreibe Blöcke mit begin, wenn ich (wie im Körper einer if Aussage) muss.

Das Problem ist, dass ich immer wieder scheinbar sehr mysteriöse Fehler bekommen habe. Ich bin mir sicher, ich mache nur einen dummen Anfängerfehler, bin neu in der Sprache, aber ich kann wirklich nicht die Quelle der Beschwerde finden.

Hier ist der problematischen Code:

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

obwohl das, was wir definieren sub-code zu scheint ziemlich irrelevant. Wenn ich es durch

ersetze, erhalte ich den gleichen Fehler. DrRacket sagt, dass in einem Ausdruck Kontext verwendet wird. Ich verstehe, was dieser Fehler normalerweise bedeuten würde - IE, dass es erhöhen würde, wenn Sie Code wie (print (define x 10)) schreiben, aber ich kann nicht sehen, was es hier auslösen würde.

Wenn es hilft, diese define ist am Anfang eines begin Block, in einer if Anweisung

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

Die spezifische Fehlermeldung DrRacket ist Druck ist

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

Ich dachte, vielleicht define isn 't erlaubt in begin Blöcke, aber ich überprüfte the docs und eines der Beispiele für begin ist

(begin 
    (define x 10) 
    x) 

Also ich weiß nicht wirklich was zu tun ist. Danke im Voraus!

Antwort

9

Definitionen sind in einem 'body'-Kontext zulässig, wie in lambda und let unter anderem. Die Folge- und Alternativsätze von if sind keine Körperkontexte; Sie sind Ausdruckskontexte und daher sind Definitionen nicht erlaubt.

begin ist speziell - begin in einem Körper Kontext ermöglicht Definitionen, aber begin in einem Ausdruck Kontexte verbietet Definitionen. Ihr Fall fällt in den späteren.

Zum Beispiel:

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

syntaktische Schlüsselwörter, die Ausdrücke erfordert: if, cond, case, and, or, when, unless, do, begin.Überprüfe die formale Syntax in jedem Scheme-Bericht (r {4,5,6,7} rs); Suchen Sie nach <body>, <sequence>, <command> und <expression>.

Auch, wenn Sie einen Körper Kontext in einem Ausdruck müssen, wickeln nur eine let syntaktische Form, wie zum Beispiel:

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

Dank! Es endete mit "Let", aber es ist nützlich zu wissen, dass 'begin' implizit so aussehen kann. Meine Intuition war, dass '(begin foo)' nur eine Kurzschrift für '((lambda() foo))' wäre, aber ich denke, es ist komplizierter als das. – SelectricSimian

6

Wie GoZoner erklärt, Sie nicht define in einem Ausdruck Kontext verwenden können.

Was könnten Sie stattdessen tun?

Verwendung let:

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

Oder es funktionieren würde mit einem "leeren" letunddefine:

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

aber das ist ein bisschen dumm.

Oder verwenden cond und define:

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

Diese letzte Art und Weise - mit cond und define - am nächsten ist, was die current Racket style guide empfiehlt.

+0

'cond' erstellt keinen Ausdruckskontext (gemäß meinem Test in R6RS und der R7RS-Entwurfsspezifikation). – GoZoner

+1

In Racket '(cond [#t (definieren x 1) x])' ist gültig und gibt '1' zurück. –

+1

Nun, wir alle wissen ... Racket ist nicht Schema ... :-) In Ikarus '(cond (#t (define foo 'foo) (Liste foo foo)))' -> "Fehler: Eine Definition wurde gefunden wo ein Ausdruck erwartet wurde. " – GoZoner

4

Hier sind weitere Details, aus der Racket-Dokumentation.

Die different contexts sind erforderlich, da Makros unterschiedlich expandieren müssen, je nachdem, welche Sprachformen zulässig sind.

Wie andere bereits gesagt haben, sind Definitionen in Ausdruckskontexten ("expr ..." in den Dokumenten) nicht erlaubt, aber in anderen Kontexten in Ordnung.

In anderen doc-Einträgen steht "body ..." für einen internen Definitionskontext (guide, reference), z. B. in Lambda-Bodies, und "form ..." gibt alle Nicht-Ausdruck-Kontexte an Dokumente für den Anfang.

0

Oder Sie könnten die Ausdrücke in (beginnen) zum Beispiel wickeln (beginnen (define x 10) (definieren y 100) (z 1000) definieren)

Verwandte Themen