Problem mit dem Dispatcher

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

Problem mit dem Dispatcher
Hmm, eigentlich hab ich das mit dem Dispatcher soweit kapiert, und ich hab auch schonmal ein Objekt gehabt, das funktioniert hat, aber heute wills irgendwie net…

Ich bekomme immer:

“#procedure:is-empty?

Wenn ich zB: (stack 'is-empty?) aufrufe (hab den stack natürlich vorher als das Objekt definiert)

mein Kot sieht so aus:
[www.rate-my-poo.com]

und mein Code so:


(define (make-stack)
  (let ((stack '()))
    
    (define (is-empty?)
      (null? stack))
    
    (define (gettop)
      (cond ((isempty? stack) (display "There is NO top, dumbass!"))
            (else (car stack))))
    
    (define (push nat)
      (cons nat stack))
    
    (define (pop)
      (set! stack (cdr stack)))
    
    (define (get)
      stack)
    
    (define (dispatch m)
      (cond ((eq? m 'is-empty?) is-empty?)
            ((eq? m 'gettop) gettop)
            ((eq? m 'push) push)
            ((eq? m 'pop) pop)
            ((eq? m 'get) get)
            (else (display "fuck off!"))))
    dispatch))

hi,

hab mir das jetzt auch mal ne weile angeschaut und herausgefunden, dass es daran liegt, dass du z. b. is-empty? als prozedur mit null parametern definierst! das ist vom prinzip her schon ok (ich wuesste keine andere loesung), aber dann muss der aufruf auch konsequent ((stack 'is-empty?)) mit zwei klammernpaaren heissen! wenn du nur ein klammernpaar machst, dann liefert er eine prozedur zurueck, der ein parameter fehlt (in unserem fall keiner). so ganz 100%ig logisch finde ich es auch nicht, aber gut, dass du gefragt hast und sich somit auch andere leute drueber gedanken machen :).
btw: im code fehlen noch ein paar sachen (z. b. set! bei push und eine fallunterscheidung bei pop), aber ich nehme an, nachdem er dir den fehler gebracht hat, ist dir die lust zum debuggen vergangen.
der vollstaendigkeit halber nochmal soweit der etwas veraenderte kot (lol uebrigens):

(define (make-stack)
  (let ((stack '()))
    
    (define (is-empty?) (null? stack))
    
    (define (gettop)
      (cond ((is-empty?) (display "there is no top to get."))
            (else (car stack))))
    
    (define (push nat)
      (set! stack (cons nat stack)))
    
    (define (pop)
      (cond ((is-empty?) (display "there is no top to pop."))
            (else (set! stack (cdr stack)))))
    
    (define (get) stack)
    
    (define (dispatch m)
      (cond ((eq? m 'is-empty?) is-empty?)
            ((eq? m 'gettop) gettop)
            ((eq? m 'push) push)
            ((eq? m 'pop) pop)
            ((eq? m 'get) get)
            (else (display "fuck off!"))))
    dispatch))

(define s (make-stack))
((s 'is-empty?))
((s 'gettop))
((s 'push) 5)
((s 'push) 3)
((s 'get))
((s 'gettop))
((s 'is-empty?))
((s 'pop))
((s 'gettop))

Okay, cool! Werd ich gleich mal ausprobieren, klingt verdammt logisch :smiley:

Das da noch Zeug fehlt wusst ich schon, aber wie du schon richtig gemutmaßt hast, hatte ich einfach keinen Bock mehr weiterzumachen…

PS: Dank dir kann ich jetzt den ganzen Samstag weiterlernen :smiley:


du wirst mir in ewigkeit dankbar sein, oder lol?


vielleicht sogar noch darüber hinaus…

Bin jetzt gerade am permutieren von listen, aber hab bis jetzt gerade mal den a) Teil auf die Beine bekommen, das reicht für heute, verdammt wir haben Wochenende!


hmm… also irgendwie funzt das immer noch nicht so recht… wenn ich ne Zahl auf den stack ge"push"t habe und mir danach den stack mit “get” ausgeben lasse ist der Stack immer noch leer…

Es ist nämlich so, dass das let den stack bei jedem neuen Aufruf von “make-stack” auf '() zurücksetzt!!

Wir müssen also unseren anfangs leeren Stack als Paramter an make-stack übergeben und diesen Aufruf an eine Variable binden (unten: Variable s), deren Zeiger dann bei jedem set! Aufruf auf einen neuen Wert umgebogen werden kann:

(define (make-stack stack)
    
    (define (is-empty?) (null? stack))
    
    (define (gettop)
      (cond ((is-empty?) (display "there is no top to get."))
            (else (car stack))))
    
    (define (push nat)
      (set! stack (cons nat stack)))
    
    (define (pop)
      (cond ((is-empty?) (display "there is no top to pop."))
            (else (set! stack (cdr stack)))))
    
    (define (get) stack)
    
    (define (dispatch m)
      (cond ((eq? m 'is-empty?) is-empty?)
            ((eq? m 'gettop) gettop)
            ((eq? m 'push) push)
            ((eq? m 'pop) pop)
            ((eq? m 'get) get)
            (else (display "fuck off!"))))

    dispatch)


(define s (make-stack '()))

was ist das bzw. was meinst du damit? hab keine ahnung, was damit gemeint sein koennte …


hmm … das finde ich wiederum komisch - wenn du den code, so wie ich ihn oben gepostet habe, in den interpreter gibst und ihn nach der make-stack-definition mit den 3 zeilen

(define s (make-stack))
((s 'push) 5)
((s 'get))

fuetterst, gibt er bei mir den korrekten stack (5) an. probiers nochmal aus!

das stimmt nicht, glaube ich. das let macht irgendwie so eine neue umgebung auf, in der der stack steht und den man mit hilfe von set! veraendern kann. ausserdem wird make-stack ja nur einmal ohne message aufgerufen - bei der definition des konkreten stacks (hier s). warum das aber alles so ist, habe ich auch keine ahnung.
vielleicht weiss jemand mehr?


schäm hast recht…

man darf halt nicht statt

((s 'get))

immer

(((make-stack) 'get))

schreiben…
da funktionierts dann mämlich net. Anscheinend geht man mit ((make-stack)) wieder in die globale Umgebung und mit s bleibt man in der von let erzeugten Umgebung…


Also ich definier immer erst mal was als mein stacky, zb:

(define stacky (make-stack))

Danach kannst du mit ((stacky 'm)) alles aufrufen, und das mit den Klammern ist inzwischen auch klar, das einzige was du ohne Klammern aufrufst sind Variablen, aber wir rufen ja “stacky” auf, und der gibt wiederum eine Prozedur zurück, die natürlich auch in Klammern stehen will.

Achja, die Permutationsaufgabe ist vom 27.03.01 die Aufgabe 4, die ist recht “cool”…


genau, und die zurueckgegebenen prozeduren erwarten evtl. auch wieder einen parameter, der muss dann in der auesseren klammer stehen, z. b. bei push: ((stacky 'push!) 5). das innere klammerpaar liefert eine prozedur zurueck und diese wird dann mit dem argument 5 aufgerufen. irgendwie braucht man schon eine ganze weile, um sich das klar machen zu koennen …


Noch ein Tipp zur Dispatch-Funktion: Man kann statt conds mit endlosen eq? auch das etwas kürzere case verwenden, das wurde zwar nicht ausführlich besprochen, bietet sich aber hier sehr an:

statt

(define (dispatch m) (cond ((eq? m 'is-empty?) is-empty?) ((eq? m 'gettop) gettop) ((eq? m 'push) push) ((eq? m 'pop) pop) ((eq? m 'get) get) (else (display "fuck off!"))))

also

(define (dispatch m) (case (m) (('is-empty?) is-empty?) (('gettop) gettop) (('push) push) (('pop) pop) (('get) get) (else (display "fuck off!"))))

case vergleicht zwar mit eqv? und nicht mit eq?, aber das ist ja in diesem Fall egal.


Der Schlüssel zur Erkenntnis scheint hier dieses ominöse Umgebungsmodell zu sein…
Wenn man sich das vor Augen hält wird schnell klar wie dieser OO-Mechanismus funzt…


klingt nicht schlecht … mal sehen.

btw: kannst du vielleicht nochmal kurz den unterschied zwischen eq, eqv und equal erklaeren (vielleicht mit beispielen)? thx in advance!