Domanda

Sto cercando di cogliere la semantica di call / cc in Scheme, e la pagina di Wikipedia su continuazioni spettacoli puzzle yin-yang come esempio:

(let* ((yin
         ((lambda (cc) (display #\@) cc) (call-with-current-continuation (lambda (c) c))))
       (yang
         ((lambda (cc) (display #\*) cc) (call-with-current-continuation (lambda (c) c)))) )
    (yin yang))

Si deve @*@**@***@****@... uscita, ma io non capisco perché; Mi aspetto che per l'uscita @*@********* ...

Qualcuno può spiegare in dettaglio perché il puzzle yin-yang funziona il modo in cui funziona?

È stato utile?

Soluzione

Non credo di comprendere appieno questo, ma posso solo pensare a una ( molto a mano ondulato) spiegazione per questo:

  • La prima @ e * vengono stampati quando yin e yang sono prima tenuti in let*. (yin yang) viene applicato, e risale verso l'alto, subito dopo la prima chiamata / cc è terminata.
  • Il prossimo @ e * sono stampati, poi un altro * è stampato perché questa volta attraverso, yin è ri-legato al valore della seconda chiamata / cc.
  • (yin yang) viene applicato di nuovo, ma questa volta è in esecuzione nell'ambiente del yang originale , dove yin è legato alla prima chiamata / cc, così il controllo torna a stampare un altro @. L'argomento yang contiene la continuazione che è stato nuovamente catturato sul secondo passaggio attraverso, che, come abbiamo già visto, si tradurrà in stampa **. Così in questo terzo passaggio, @* verrà stampato, quindi questa continuazione stella doppia-stampa viene invocata, in modo che finisce con 3 stelle, e quindi questa triplice stelle continuazione è ri-catturato, ...

Altri suggerimenti

Understanding Scheme

Credo che almeno la metà del problema con la comprensione di questo puzzle è la sintassi Scheme, che la maggior parte non hanno familiarità con.

Prima di tutto, io personalmente trovare il call/cc x ad essere più difficile da comprendere che l'alternativa equivalente, x get/cc. E 'ancora chiamate x, passandogli la continuazione corrente , ma in qualche modo è più suscettibili di essere rappresentati nel mio circuiti cerebrali.

Con questo in mente, il (call-with-current-continuation (lambda (c) c)) costrutto diventa semplicemente get-cc. Ora siamo a questo:

(let* ((yin
         ((lambda (cc) (display #\@) cc) get-cc))
       (yang
         ((lambda (cc) (display #\*) cc) get-cc)) )
    (yin yang))

Il passo successivo è il corpo del lambda interna. (display #\@) cc, nella sintassi più familiare (per me, comunque) significa print @; return cc;. Mentre noi siamo, diamo anche riscrivere lambda (cc) body come function (arg) { body }, rimuovere un po 'di parentesi, e chiamate di funzione modifica al C-come la sintassi, per arrivare a questo:

(let*  yin =
         (function(arg) { print @; return arg; })(get-cc)
       yang =
         (function(arg) { print *; return arg; })(get-cc)
    yin(yang))

Sta cominciando ad avere più senso ora. Ora è un piccolo passo per riscrivere questo completamente in C-sintassi simile (o JavaScript simile, se si preferisce), per arrivare a questo:

var yin, yang;
yin = (function(arg) { print @; return arg; })(get-cc);
yang = (function(arg) { print *; return arg; })(get-cc);
yin(yang);

La parte più difficile è finita, abbiamo decodificato questo da Scheme! Stavo solo scherzando; era difficile solo perché non avevo alcuna esperienza precedente con Scheme. Quindi, andiamo a capire come funziona in realtà.

Un primer su continuazioni

Osservare il nucleo stranamente formulata di yin e yang: definisce una funzione e poi immediatamente chiama . Sembra proprio come (function(a,b) { return a+b; })(2, 3), che può essere semplificata in 5. Ma semplificare le chiamate all'interno di yin / yang sarebbe un errore, perché non stiamo passando un valore normale. Stiamo passando la funzione di un continuazione .

Una continuazione è una bestia strana a prima vista. Prendere in considerazione il programma molto più semplice:

var x = get-cc;
print x;
x(5);

Inizialmente x è impostato l'oggetto prosecuzione corrente (orso con me), e print x viene eseguito, la stampa qualcosa come <ContinuationObject>. Fin qui tutto bene.

Ma una continuazione è come una funzione; può essere chiamato con un argomento. Ciò che fa è:. Prendere l'argomento, e quindi salto per ovunque che la continuazione è stato creato, il ripristino di tutto contesto, e facendo in modo che i rendimenti get-cc questo argomento

Nel nostro esempio, l'argomento è 5, così abbiamo essenzialmente salto indietro proprio nel bel mezzo di quella dichiarazione var x = get-cc, solo che questa volta torna get-cc 5. Così x diventa 5, e l'istruzione successiva continua a stampare 5. Dopo che cerchiamo di chiamata 5(5), che è un errore di tipo, e il programma si blocca.

Si noti che chiamare la continuazione è un salto , non è una chiamata. Non è mai ritorna al punto in cui è stato chiamato il proseguimento. Questo è importante.

Come funziona il programma

Se avete seguito che, allora non ci si illuda: questa parte è davvero la più difficile. Ecco il nostro programma di nuovo, lasciando cadere le dichiarazioni di variabili, perché questo è pseudo-codice in ogni caso:

yin = (function(arg) { print @; return arg; })(get-cc);
yang = (function(arg) { print *; return arg; })(get-cc);
yin(yang);

La prima linea del tempo 1 e 2 sono colpiti, sono semplici ora: ottenere la continuazione, chiamare la funzione (arg), @ stampa, cambio, negozio che la continuazione in yin. Stessa cosa con yang. Ora abbiamo stampato @*.

Avanti, chiamiamo alla prosecuzione nel yin, passando yang. Questo ci fa saltare per la linea 1, proprio all'interno che get-cc, e farla tornare yang invece. Il valore di yang è ora passato alla funzione, che stampa @, e poi restituisce il valore di yang. Ora yin è assegnato che la continuazione che yang ha. Poi abbiamo appena procede alla linea 2: get c / c, * stampare, archiviare °e c / c in yang. Ora abbiamo @*@*. E, infine, andiamo a linea 3.

Ricordate che yin ora ha la continuazione dal momento in cui è stato eseguito prima linea 2. Così saltiamo alla linea 2, la stampa di un secondo * e l'aggiornamento yang. Ora abbiamo @*@**. Infine, chiamare di nuovo la continuazione yin, che salterà per la linea 1, la stampa di un @. E così via. Francamente, a questo punto il mio cervello genera un'eccezione OutOfMemory e perdo traccia di tutto ciò. Ma almeno abbiamo avuto modo di @*@**!

Questo è difficile da seguire e ancora più difficile da spiegare, ovviamente. Il modo perfetto per fare questo sarebbe fare un passo attraverso di essa in un debugger che può rappresentare continuazioni, ma ahimè, non so di qualsiasi. Spero che abbiate goduto di questo; Certamente ho.

Musings prima, possibile risposta alla fine.

Credo che il codice può essere riscritto in questo modo:

; call (yin yang)
(define (yy yin yang) (yin yang))

; run (call-yy) to set it off
(define (call-yy)
    (yy
        ( (lambda (cc) (display #\@) cc) (call/cc (lambda (c) c)) )
        ( (lambda (cc) (display #\*) cc) (call/cc (lambda (c) c)) )
     )
)

O con alcune dichiarazioni di visualizzazione in più per aiutare a vedere che cosa sta accadendo:

; create current continuation and tell us when you do
(define (ccc)
    (display "call/cc=")
    (call-with-current-continuation (lambda (c) (display c) (newline) c))
)

; call (yin yang)
(define (yy yin yang) (yin yang))

; run (call-yy) to set it off
(define (call-yy)
    (yy
        ( (lambda (cc) (display "yin : ") (display #\@) (display cc) (newline) cc) 
            (ccc) )
        ( (lambda (cc) (display "yang : ") (display #\*) (display cc) (newline) cc) 
            (ccc) )
     )
)

O come questa:

(define (ccc2) (call/cc (lambda (c) c)) )
(define (call-yy2)
    (
        ( (lambda (cc) (display #\@) cc) (ccc2) )
        ( (lambda (cc) (display #\*) cc) (ccc2) )
    )
)

possibile risposta

Questo non può essere giusto, ma io avere un andare.

Credo che il punto chiave è che un 'chiamato' la continuazione restituisce la pila a uno stato precedente - come se non altro fosse accaduto. Naturalmente non sa che abbiamo il monitoraggio è visualizzando personaggi @ e *.

Inizialmente definiamo yin essere un A continuazione che farà questo:

1. restore the stack to some previous point
2. display @
3. assign a continuation to yin
4. compute a continuation X, display * and assign X to yang
5. evaluate yin with the continuation value of yang - (yin yang)

Ma se chiamiamo una continuazione yang, questo accade:

1. restore the stack to some point where yin was defined
2. display *
3. assign a continuation to yang
4. evaluate yin with the continuation value of yang - (yin yang)

Si comincia qui.

La prima volta che si ottiene attraverso yin=A e yang=B come yin e yang vengono inizializzati.

The output is @*

(Sia continuazioni A e B sono calcolati.)

Ora (yin yang) viene valutato come (A B) per la prima volta.

Sappiamo cosa A fa. Lo fa:

1. restores the stack - back to the point where yin and yang were being initialised.
2. display @
3. assign a continuation to yin - this time, it is B, we don't compute it.
4. compute another continuation B', display * and assign B' to yang

The output is now @*@*

5. evaluate yin (B) with the continuation value of yang (B')

Ora (yin yang) viene valutato come (B B').

Sappiamo cosa B fa. Lo fa:

1. restore the stack - back to the point where yin was already initialised.
2. display *
3. assign a continuation to yang - this time, it is B'

The output is now @*@**

4. evaluate yin with the continuation value of yang (B')

Dal momento che lo stack è stato riportato al punto in cui yin=A, (yin yang) viene valutato come (A B').

Sappiamo cosa A fa. Lo fa:

1. restores the stack - back to the point where yin and yang were being initialised.
2. display @
3. assign a continuation to yin - this time, it is B', we don't compute it.
4. compute another continuation B", display * and assign B" to yang

The output is now @*@**@*

5. evaluate yin (B') with the continuation value of yang (B")

Sappiamo cosa B' fa. Lo fa:

1. restore the stack - back to the point where yin=B.
2. display *
3. assign a continuation to yang - this time, it is B"

The output is now @*@**@**

4. evaluate yin (B) with the continuation value of yang (B")

Ora (yin yang) viene valutato come (B B").

Sappiamo cosa B fa. Lo fa:

1. restore the stack - back to the point where yin=A and yang were being initialised.
2. display *
3. assign a continuation to yang - this time, it is B'"

The output is now @*@**@***

4. evaluate yin with the continuation value of yang (B'")

Dal momento che lo stack è stato riportato al punto in cui yin=A, (yin yang) viene valutato come (A B'").

.......

Credo che abbiamo un modello ora.

Ogni volta che noi chiamiamo (yin yang) abbiamo ciclo attraverso una pila di continuazioni B fino ad arrivare indietro a quando yin=A e visualizziamo @. Il ciclo che attraverso la pila di continuazioni B la scrittura di un * ogni volta.

(sarei davvero felice se questo è più o meno a destra!)

Grazie per la domanda.

YinYang puzzle è scritto nello Schema. Suppongo che si conosce la sintassi di base dello schema.

Ma suppongo che non sai let* o call-with-current-continuation, spiegherò queste due parole chiave.

Spiegare let*

Se sai già che, si può saltare a Explain call-with-current-continuation

let*, che si presenta come let, agisce come let, ma valuterà le sue variabili definite (il (yin ...) e (yang ...)) uno per uno e con entusiasmo. Ciò significa, in primo luogo valutare yin, e di yang.

Si può leggere di più qui: Utilizzando Let nello Schema

Spiegare call-with-current-continuation

Se sai già che, si può passare alla Yin-Yang puzzle.

E 'un po' difficile da spiegare call-with-current-continuation. Quindi userò una metafora per spiegare.

Immagine di un mago che conosceva un incantesimo, che era call-with-current-continuation. Una volta lanciato l'incantesimo, avrebbe creato un nuovo universo, e lo sé inviare ad esso. Ma poteva fare nulla nel nuovo universo, ma in attesa di qualcuno che chiama il suo nome. Una volta che stato chiamato , la procedura guidata sarebbe tornato per l'universo originale, avendo il povero ragazzo - 'qualcuno' - in mano, e andare sulla sua vita procedura guidata. Se non è stato chiamato, quando il nuovo universo si è conclusa, la procedura guidata anche restituito all'universo originale.

Ok, cerchiamo di essere più tecnico.

call-with-current-continuation è una funzione che accetta una funzione come parametro. Una volta che si chiama call-with-current-continuation con una funzione F, sarà imballare l'ambiente in esecuzione corrente, che si chiama current-continuation, come parametro C, ed inviarlo alla funzione F, ed eseguire F. Così l'intero programma diventa (F C). O essere più JavaScript: F(C);. C agisce come una funzione. Se C non è rimessa in F, allora è un programma ordinario, al ritorno F, call-with-current-continuation ha un valore come valore di ritorno di F. Ma se C viene chiamato con un parametro V, cambierà di nuovo l'intero programma. Il programma cambia di nuovo ad un Stato quando call-with-current-continuation stato chiamato. Ma ora call-with-current-continuation produce un valore, che è V. E il programma continua.

Facciamo un esempio.

(define (f return)
  (return 2)
  3)
(display (f whatever)) ;; 3
(display (call-with-current-continuation f)) ;; 2
(display (call-with-current-continuation (lambda (x) 4))) ;; 4

La prima uscita display 3, di causa.

Ma la seconda uscita display 2. Perché?

tuffo Let in esso.

Nel valutare (display (call-with-current-continuation f)), in primo luogo valutare (call-with-current-continuation f). Sappiamo che cambierà l'intero programma a

(f C)

Considerando la definizione f, ha un (return 2). Dobbiamo valutare (C 2). Questo è quando il continuation chiamato. Quindi modificare il programma intero torna a

(display (call-with-current-continuation f))

Ma ora, call-with-current-continuation ha valore 2. Così il programma diventa:

(display 2)

Yin-Yang di puzzle

Diamo un'occhiata al puzzle.

(let* ((yin
         ((lambda (cc) (display #\@) cc) (call-with-current-continuation (lambda (c) c))))
       (yang
         ((lambda (cc) (display #\*) cc) (call-with-current-continuation (lambda (c) c)))))
      (yin yang))

make Ammettiamolo più leggibile.

(define (id c) c)
(define (f cc) (display #\@) cc)
(define (g cc) (display #\*) cc)
(let* ((yin
         (f (call-with-current-continuation id)))
       (yang
         (g (call-with-current-continuation id))))
      (yin yang))

corsa di lasciare che il programma nel nostro cervello.

rotonda 0

let* fanno di valutare yin prima. yin è

(f (call-with-current-continuation id))

Quindi valutiamo prima (call-with-current-continuation id). Imballa contesto attuale, che noi chiamiamo C_0 distinguere con altri prosecuzione nel time-line, ed entra in un nuovo universo: id. Ma id restituisce solo C_0.

Dobbiamo ricordare ciò che è C_0. C_0 è un programma come questo:

(let* ((yin
         (f ###))
       (yang
         (g (call-with-current-continuation id))))
      (yin yang))

### è un segnaposto, che in futuro sarà riempito dal valore che C_0 riprende.

Ma id restituisce solo C_0. Essa non chiama C_0. Se si chiama, entreremo l'universo di C_0. Ma non lo fece, così continuiamo a valutare yin.

(f C_0) ;; yields C_0

f è una funzione come id, ma ha un effetto collaterale -. Emettere @

Così il @ output del programma e lasciare yin di essere C_0. Ora il programma diventa

(let* ((yin C_0)
       (yang
         (g (call-with-current-continuation id))))
      (yin yang))

Dopo yin valutato, iniziamo a valutare yang. yang è

(g (call-with-current-continuation id))

call-with-current-continuation qui creare un altro seguito, di nome C_1. C_1 è:

(let* ((yin C_0)
       (yang
         (g ###)))
      (yin yang))

### è segnaposto. Si noti che in questo seguito, il valore di yin è determinato (che è quello che let* fare). Siamo sicuri che il valore di yin è C_0 qui.

Dal (id C_1) è C_1, quindi il valore di yang è

(g C_1)

g ha un effetto collaterale - output *. Così fa il programma.

Il valore di yang è ora C_1.

@*

A questo punto, abbiamo visualizzato

Così ora diventa:

(let* ((yin C_0)
       (yang C_1))
      (yin yang))

Per quanto sia yin e yang sono risolti, dovremmo valutare (yin yang). E '

(C_0 C_1)

Santo sh * t!

Ma alla fine, C_0 si chiama. Così voliamo nell'universo C_0 e dimenticare tutto su questi sh * ts. Non riusciremo mai a tornare a questo universo di nuovo.

Round 1

take C_0 con schienale C_1. Il programma diventa ora (Se si dimentica quello che sta per C_0, torna a vedere):

(let* ((yin
         (f C_1))
       (yang
         (g (call-with-current-continuation id))))
      (yin yang))

Ah, troviamo il valore di quel yin non è ancora determinato. Quindi valutiamo esso. Nel processo di valutazione yin, abbiamo uscita un @ come effetto collaterale di f. E sappiamo yin è C_1 ora.

Iniziamo a valutare yang, ci siamo imbattuti in call-with-current-continuation di nuovo. Ci sono praticati. Creiamo un C_2 continuazione, che significa:

(let* ((yin C_1)
       (yang
         (g ###)))
      (yin yang))

E abbiamo visualizzare un * come g esecuzione. E veniamo qui

(let* ((yin C_1)
       (yang C_2))
      (yin yang))

Così abbiamo ottenuto:

(C_1 C_2)

Non si sa dove stiamo andando. Stiamo per l'universo di C_1. Ricordiamo a memoria (o copiare e incollare dalla pagina web). E 'ora:

(let* ((yin C_0)
       (yang
         (g C_2)))
      (yin yang))

Sappiamo nell'universo di C_1, il valore di yin è stata determinata. Quindi iniziamo a valutare yang. Come ci si praticano, io direttamente dirvi che visualizza * e diventa:

(C_0 C_2)

@*@** Ora abbiamo stampato, e ci accingiamo a presa nell'universo di C_0 con C_2.

Round 2

Come ci si praticano, io vi dirà che visualizziamo '@', yin è C_2, e creiamo un nuovo C_3 continuazione, che significa:

(let* ((yin C_2)
       (yang
         (g ###)))
      (yin yang))

E visualizziamo *, yang è C_3, e diventa

(C_2 C_3)

E possiamo continuare. Ma mi fermo qui, vi ho mostrato la prima cosa che più uscite di Yin-Yang di puzzle sono.

Perché il numero di aumenti *?

Ora la testa è piena di dettagli. Farò una sintesiper voi.

I userà un Haskell come sintassi per semplificare. E cc è l'abbreviazione di call-with-current-continuation.

Quando #C_i# viene variata da #, significa che la prosecuzione è creare qui. mezzi ; uscita


yin = f cc id
yang = g cc id
yin yang

---

yin = f #C_0# ; @
yang = g cc id
yin yang

---

yin = C_0
yang = g #C_1# ; *
yin yang

---

C_0 C_1

---

yin = f C_1 ; @
yang = g #C_2# ; *
yin yang

---

C_1 C_2

---

yin = C_0
yang = g C_2 ; *
yin yang

---

C_0 C_2

---

yin = f C_2 ; @
yang = g #C_3#; *
yin yang

---

C_2 C_3

---

yin = C_1
yang = g C_3 ; *
yin yang

---

C_1 C_3

---

yin = C_0
yang = g C_3 ; *
yin yang

---

C_0 C_3

Se si osserva con attenzione, sarà ovvio che

  1. Ci sono un sacco di universi (in realtà infinita), ma C_0 è l'unico universo che ha iniziato da f. Altri sono iniziate da g.
  2. C_0 C_n fa sempre un nuovo C_max continuazione. È perché C_0 è il primo universo che g cc id ha non stato eseguito.
  3. C_0 C_n visualizzare anche @. C_n C_m cui n non è 0 visualizzerà *.
  4. di volta in volta il programma si deduce a C_0 C_n, e io dimostrare che C_0 C_n è separato da un'espressione più e più altri, che porta a @*@**@***...

Un po 'di matematica

Si supponga C_n (n! = 0) è il più grande numero in tutte le continuazioni, e quindi C_0 C_n si chiama .

Assunzione:. Quando C_0 C_n viene chiamato, C_n è la corrente massima prosecuzione numerata

Ora C_ {n + 1} viene creato da C_0 C_n in questo modo:

yin = f C_n ; @
yang = g #C_{n+1}#
yin yang

Quindi, possiamo concludere che:

Teorema I. Se C_0 C_n si chiama, si produrrà una continuazione C_ {n + 1} , nella quale è yin C_n .

Poi passo successivo è C_n C_{n+1}.

yin = C_{n-1}
yang = g C_{n+1} ; *
yin yang

Il motivo per cui è yin C_{n-1} è che quando C_n essere creato obbedì Teorema I .

E poi C_{n-1} C_{n+1} si chiama, e sappiamo quando si crea C_{n-1}, ma anche obbedito Teorema I . Così abbiamo C_{n-2} C_{n+1}.

C_{n+1} è l'in-variante. Così abbiamo il secondo teorema:

teorema II. Se C_n C_m che n < m e n > 0 si chiama, diventerà C_{n-1} C_m.

E abbiamo manualmente controllati C_0 C_1 C_2 C_3. Obbediscono dell'Assunta e tutti i teoremi. E sappiamo come primo @ e * si viene a creare.

Quindi possiamo scrivere i modelli qui di seguito.

C_0 C_1 ; @ *
C_[1-0] C_2 ; @ * *
C_[2-0] C_3 ; @ * * *
...

Non così severo, ma mi piacerebbe scrivere:

Q.E.D.

Come un'altra risposta, ha detto, abbiamo (call-with-current-continuation (lambda (c) c)) primo semplificare con get-cc.

(let* ((yin
         ((lambda (cc) (display #\@) cc) get-cc))
       (yang
         ((lambda (cc) (display #\*) cc) get-cc)) )
    (yin yang))

Ora, i due lambda sono solo una funzione identica associato con effetti collaterali. Chiamiamo quelle funzioni f (per display #\@) e g (per display #\*).

(let* ((yin (f get-cc))
       (yang (g get-cc)))
    (yin yang))

Avanti abbiamo bisogno di lavorare fuori l'ordine di valutazione. Per essere chiari, io introdurrà una "espressione step" che rende ogni fase di valutazione esplicita. Prima di tutto chiedono: qual è la funzione di cui sopra richiede

Si richiede definizioni di f e g. In fase di espressione, scriviamo

s0 f g =>

Il primo passo è quello di calcolare yin, ma che richiedono la valutazione di (f get-cc), e la successiva richiede get-cc.

In parole povere, get-cc ti dà un valore che rappresenta la "continuazione corrente". Diciamo che questo è s1 poiché questo è il passo successivo. Così scriviamo

s0 f g => s1 f g ?
s1 f g cc =>

Si noti che i parametri sono scopeless, che significa che la f e g in s0 e s1 non sono necessari lo stesso e sono da utilizzare solo all'interno del passo corrente. Questo rende le informazioni di contesto esplicito. Ora, qual è il valore per cc? Poiché è "continuazione di", è sorta la stessa s1 con f e g vincolato allo stesso valore.

s0 f g => s1 f g (s1 f g)
s1 f g cc =>

Una volta che abbiamo cc, possiamo valutare f get-cc. Inoltre, dal momento che f non viene utilizzato nel codice seguente, non abbiamo di trasmettere questo valore.

s0 f g => s1 f g (s1 f g)
s1 f g cc => s2 g (f cc)
s2 g yin =>

Il prossimo è il simile per yang. Ma ora abbiamo un valore di più di trasmettere:. yin

s0 f g => s1 f g (s1 f g)
s1 f g cc => s2 g (f cc)
s2 g yin => s3 g yin (s3 g yin)
s3 g yin cc => s4 yin (g cc)
s4 yin yang => 

Infine, l'ultimo passo è quello di applicare yang a yin.

s0 f g => s1 f g (s1 f g)
s1 f g cc => s2 g (f cc)
s2 g yin => s3 g yin (s3 g yin)
s3 g yin cc => s4 yin (g cc)
s4 yin yang => yin yang

Questa finito il costrutto di espressione passo. Tradurre di nuovo a schema è semplice:

(let* ([s4 (lambda (yin yang) (yin yang))]
       [s3 (lambda (yin cc) (s4 yin (g cc))]
       [s2 (lambda (yin) (s3 yin ((lambda (cc) (s3 yin cc))))]
       [s1 (lambda (cc) (s2 (f cc)))])
      (s1 s1))

L'ordine valutazione dettagliata (qui lambda all'interno del corpo di s2 stato semplicemente espressa come parziale s3 yin valutazione anziché (lambda (cc) (s3 yin cc))):

(s1 s1)
=> (s2 (f s1))
=> @|(s2 s1)
=> @|(s3 s1 (s3 s1))
=> @|(s4 s1 (g (s3 s1)))
=> @*|(s4 s1 (s3 s1))
=> @*|(s1 (s3 s1))
=> @*|(s2 (f (s3 s1)))
=> @*@|(s2 (s3 s1))
=> @*@|(s2 (s3 s1))
=> @*@|(s3 (s3 s1) (s3 (s3 s1)))
=> @*@|(s4 (s3 s1) (g (s3 (s3 s1))))
=> @*@*|(s4 (s3 s1) (s3 (s3 s1)))
=> @*@*|(s3 s1 (s3 (s3 s1)))
=> @*@*|(s4 s1 (g (s3 (s3 s1))))
=> @*@**|(s4 s1 (s3 (s3 s1)))
=> @*@**|(s1 (s3 (s3 s1)))
=> ...

(Ricordate, quando si valutano s2 o s4, il parametro sta per essere valutati prima

Questo un vecchio puzzle Da maestro di offuscamento David Madore, che creato Unlambda. Il puzzle è stato discusso comp.lang.scheme diversi volte.

Una soluzione piacevole da Taylor Campbell: https://groups.google.com/d/msg/comp .lang.scheme / pUedvrKYY5w / uIjTc_T1LOEJ

Il post originale da David Madore (1999): https://groups.google.com/d/msg/comp .lang.scheme / Fysq_Wplxsw / awxEZ_uxW20J

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top