2012-03-08 11 views
5

Il problema è il seguente e trovato in http://www.cs.indiana.edu/classes/b551-leak/scheme_practice.html.Come passare una stringa come nome di funzione nello schema? [Costruzione dinamica dei nomi delle funzioni in Schema]

Definizione del problema: Scrivere una funzione cxr che è una generalizzazione degli operatori di auto/cdr forniti in Schema. cxr dovrebbe prendere una stringa di "a" e "d" che rappresenta la sequenza di operazioni di auto e cdr da eseguire e restituire una funzione in grado di eseguire quella sequenza.

Quindi (cxr "annuncio") è equivalente alla funzione cadr.

((cxr "ad") '(i ii iii iv v vi vii)) ==> ii 
    (define sixth (cxr "addddd")) 
    (sixth '(i ii iii iv v vi vii))   ==> vi 

Il mio tentativo: ho convertito cxr "annuncio" in una stringa "CADR" usando stringhe accodamento. [Questo è facile] .. Ora come posso collegare tra "cadr" con cadr ... Ho provato il simbolo string->, ma l'output è quotato e da cui la funzione non viene eseguita. - Quindi c'è un modo per smontare ?!

La vera domanda: come risolvere questo problema?


UPDATE: Grazie a tutti per queste risposte. Sono tutti corretti e l'ho risolto in questo modo prima ancora di pubblicare la domanda. Stavo principalmente cercando un modo per chiamare effettivamente caddddr quando l'input è (cxr adddd) ... Everbody ha fatto la stessa funzionalità di caddddr ma in realtà non ha chiamato cadddr.

Cioè, come fare le funzioni di wit lo stesso tipo di denominazione come CADR Caddr ecc


UPDATE: (Credo di avere trovato la soluzione ed è come segue - ma come si narra di sotto di essa non funziona per più d's):

(define cxr 
(lambda (ad l) 
    ((eval (string->symbol (string-append "c" ad "r"))) l) 
) 
) 
+0

Penso che l'idea sia di scrivere un generatore di funzioni dall'informazione nella stringa. – zellio

risposta

5

Come Mimisbrunnr sottolinea, l'idea qui non è a stringa-append e quindi eval. Per prima cosa, questo non funzionerà per sequenze più lunghe di a's e d's.

Invece, si desidera scrivere una funzione che consuma una stringa e restituisce una funzione analizzando la stringa carattere per carattere.

In linguaggio HtDP, questo potrebbe essere eseguito come ricorsione strutturale in un elenco di "a" se "d" s, dopo aver convertito la stringa in un elenco.

Per semplificare, è possibile utilizzare "stringa-> elenco". Questo esiste in Racket, e ho la vaga sensazione che sia anche parte di r5rs.

+0

vedere l'aggiornamento per la risposta corretta – AJed

+0

corretto? Yecch! Non * scrivere * questa funzione in questo modo. :) –

+0

Oh! ahah! :)) Ho avuto la tua soluzione molto prima .. Stavo solo cercando "generazione dinamica di funzioni" - non deve essere necessario la funzione cxr – AJed

3

Tu chiedi: "Adesso come posso creare un collegamento tra "CADR" con CADR

Prima possiamo collegare i caratteri # \ a per auto e # \ d per CDR:.

(define (x->cxr x) 
    (if (eqv? x #\a) car cdr)) 

Esempio :

> ((x->cxr #\a) '(foo bar)) 
'foo 

quindi utilizzare il fatto che cadr è la composizione di car e cdr (come in CADR è (compose car cdr).

(define (cxr s) 
    (apply compose 
     (map x->cxr 
       (string->list s)))) 
+0

Nella descrizione del problema si dice cxr è una funzione, quindi ha bisogno di valutare il suo input. Ho chiarito cosa intendevo per "cadr è una composizione di auto e cdr – soegaard

1

Ecco una possibile implementazione, un mini-interprete per un elenco di operazioni da applicare su un dato di input:

(define (cxr ops) 
    (lambda (input) 
    (generate-cxr (reverse (string->list ops)) input))) 

(define (generate-cxr ops-list acc) 
    (if (null? ops-list) 
     acc 
     (generate-cxr (cdr ops-list) (operate (car ops-list) acc)))) 

(define (operate op input) 
    (cond ((eqv? op #\a) (car input)) 
     ((eqv? op #\d) (cdr input)) 
     (else (error "unknown operation" op)))) 

ho diviso il problema in tre parti:

  1. cxr restituisce una funzione che, quando chiamata, elaborerà il suo input rispetto alla sequenza di operazioni ricevute come parametro. Si noti che l'elenco delle operazioni viene elaborato nell'ordine inverso in cui sono state dichiarate
  2. generate-cxr processi ciascuna operazione in volta, fino a quando non più operazioni vengono lasciate eseguire, accumulando il risultato
  3. operate decide quale operazione da applicare e realtà esegue, restituendo il risultato

Le procedure sopra riportate restituiscono una risposta corretta ma è molto inefficiente, perché l'analisi sintattica delle operazioni è intercalata con la loro esecuzione. È possibile separare l'analisi sintattica dall'esecuzione, producendo una soluzione più rapida. Vedere la sezione 4.1.7 in SICP.

+0

Poiché il comportamento di eq applicato ai caratteri è dipendente dall'implementazione, suggerisco di utilizzare eqv ?. – soegaard

+0

suggerimento @soegaard accettato, grazie! –

1

EDIT: In risposta alla tua aggiornamento, penso che si vuole fare qualcosa di simile:

(eval `(define ,<procedure-to-return-symbol> ,<value>) <environment>) 

esempio nel mit-schema:

(eval `(define ,(string->symbol "abc") ,(* 2 2)) user-initial-environment) 

Dove user-initial-environment è l'ambiente in cui i simboli sono internati quando digitato nel REPL. Questo esempio restituirà il simbolo abc associato al valore 4. Utilizzando questo metodo sarà possibile utilizzare la procedura per creare il nome e associarlo al valore restituito dalla mia soluzione di seguito. Puoi leggere ulteriori informazioni su eval e sugli ambienti mit-scheme here. </edit>

EDIT2: una soluzione esplicita:

(define (cxr x) 
    (define (helper xlist arg) 
    (cond ((null? xlist) arg) 
      ((eq? (car xlist) #\a) (car (helper (cdr xlist) arg))) 
      ((eq? (car xlist) #\d) (cdr (helper (cdr xlist) arg))) 
      (else (error "INVALID ARGS FOR CXR")))) 
    (eval `(define ,(string->symbol (string-append "c" x "r")) 
      ,(lambda (arg) (helper (string->list x) arg))) user-initial-environment)) 

In questo modo è possibile creare il nome procedure per qualsiasi profondità di stringhe "Ad". </edit>

La soluzione iniziale è utilizzabile al meglio quando sono già presenti composizioni di car e cdr. Il problema è la ricerca di una procedura che restituisca una procedura che porta la macchina/cdr di una lista a una profondità arbitraria. Questa è la mia soluzione:

(define (cxr x) 
    (define (helper xlist arg) 
    (cond ((null? xlist) arg) 
      ((eq? (car xlist) #\a) (car (helper (cdr xlist) arg))) 
      ((eq? (car xlist) #\d) (cdr (helper (cdr xlist) arg))) 
      (else (error "INVALID ARGS FOR CXR")))) 
    (lambda (arg) (helper (string->list x) arg))) 

helper corre verso il basso l'elenco dei A e d's chiamando il sia car o cdr sul risultato della prossima chiamata a helper - si costruisce il corpo per il lambda. Quando l'elenco è vuoto, helper restituisce arg che è il parametro per l'espressione lambda. Poiché il modulo lambda non ha un argomento passato ad esso nella definizione, cxr restituirà una procedura.

+0

Si prega di vedere sopra: Immagino di aver appena trovato la soluzione, - grazie! Non ho ancora provato la tua soluzione, lo proverò ora! – AJed

+0

Il tuo aggiornamento non sembra chiamare correttamente 'eval' - richiede una variabile di ambiente. la mia seconda modifica per una soluzione esplicita. – oobivat