2014-04-06 8 views
5

Sto provando a racchiudere le funzioni con i raffinamenti in un modo generico in modo che possano essere chiamati senza il raffinamento. Per esempio, invece di ARRAY-INITIAL size valueARRAY/INITIAL size valueCome concludere una funzione con un raffinamento in modo che il raffinamento non sia richiesto?

wrap: function [refined [path!] args [block!]] [ 
    function args compose [ 
     (refined) (args) 
    ] 
] 

array-initial wrap 'array/initial [size value] 

Non troppo di fantasia. Sembra funzionare in generale, ma questo ha qualcosa di strano se lo si chiama usando una funzione:

>> n: 0 array/initial 4 does [++ n] 
== [10 11 12 13] 

>> n: 10 array-initial 4 does [++ n] 
== [10 10 10 10] 

Quando ho source che ottengo questo:

>> source array-initial 
array-initial: make function! [[size value][array/initial size value]] 

Okay, quindi quello che sta succedendo è che la funzione è chiamato nel wrapper e il risultato della chiamata passata ... non la funzione. Una soluzione sarebbe quella di utilizzare un get-word per evitare la valutazione:

>> array-initial-2: function [size value] [array/initial size :value] 

>> array-initial-2: 10 array-initial-2 4 does [++ n] 
[10 11 12 13] 

ma ero alla ricerca di un approccio generale. Qual è il modo migliore per eseguire il proxy dei parametri senza che ciò accada?

+0

@ endo64 È [aggiunto una copia] (http://stackoverflow.com/revisions/22892499/3) ... questa è la funzione Rebol2. In Rebol3 è stata presa la decisione di eliminare quella forma di FUNZIONE ... ora è quello che un tempo era conosciuto come FUNCT. Più user-friendly in questo modo (e compatibile con Red). Il mio suggerimento è che, in pratica, proviamo solo ad asciare tutti gli usi FUNCTION in campioni di codice Rebol2 e poi a passare da FUNCT a FUNCTION in Rebol3. – HostileFork

+0

Oh, giusto, l'ho dimenticato. – endo64

risposta

1

Questo è stato un esercizio affascinante, devo amare COSÌ.

scopre che in realtà bisogno di un "do ridurre" per avvolgere le funzioni con argomenti get-word ...

R3 solo al momento:

unrefine: func [ 
    "Return an equivalent function with the given refinements wired in." 
    refined [any-path! block!] "The function, with the refinements to include." 
    /local ospec spec body found p s w b r 
] [ 
    ospec: spec-of get first refined: to lit-path! :refined 
    body: append copy spec: make block! length? ospec copy/deep [do reduce []] 
    append/only body/3 :refined 
    parse ospec [ 
    set s 0 1 string! (all [s append spec s]) 
    any [ 
     set w [word! | get-word! | lit-word!] (
     append spec :w 
     append body/3 either word! = type? :w [reduce ['quote to get-word! w]][w]) 
     set b 0 1 block! (
     all [b append/only spec copy b]) 
     set s 0 1 string! (
     all [s append spec copy s]) 
    | 
     /local to end 
    | 
     set r refinement! (
     p: any [p tail spec] 
     if not found: find next refined r [append spec r]) 
     set s 0 1 string! (all [not found s append spec copy s]) 
     any [ 
     set w [word! | get-word! | lit-word!] (
      either found [p: insert p :w][append spec :w] 
      append body/3 either word! = type? :w [reduce ['quote to get-word! w]][w]) 
     set b 0 1 block! (
      all [b either found [p: insert/only p copy b][append/only spec copy b]]) 
     set s 0 1 string! (
      all [s either found [p: insert p copy s][append spec copy s]]) 
     ] 
    ] 
    ] 
    func spec body 
] 
+0

Questo è un boccone! Ma andremo con questo come risposta per ora, in ogni caso. – HostileFork

1

Credo che l'approccio generale sia che bisogna tenere conto del modo in cui le parole vengono utilizzate all'interno degli argomenti delle funzioni e passate alle funzioni.

wrap: func [ 
    'refined [path!] 
    args [block!] 
][ 
    func map-each arg args [ 
     either get-word? :arg [to word! arg] [:arg] 
    ] compose [ 
     (refined) (
      map-each arg args [ 
       either lit-word? :arg [to get-word! arg] [:arg] 
      ] 
     ) 
    ] 
] 

Ci sono due problemi qui: le parole che definiscono la funzione e le parole passate alla funzione. Il primo si presenta in due forme principali: word! per argomenti normali e lit-word! per argomenti letterali. Nelle nostre specifiche, se abbiamo la parola d'ordine ! argomenti, vogliamo che siano argomenti normali e convertire in parola !. Quando si tratta di passare argomenti, ancora una volta abbiamo due forme: parola! per valutare l'argomento e get-word! per passare il valore a cui punta la parola. Se le nostre specifiche gestiscono una parola illuminata !, dobbiamo passare un get-word ! come una parola ! verrà passato letteralmente.

Speriamo che tutto abbia un senso!

In ogni caso, come questo gioca fuori è:

wrapped-foobar: wrap foo/bar ['literal evaluated :referred] 

Abbiamo i nostri tre tipi, il primo consente di passare valori attraverso letteralmente, ad esempio parole senza utilizzare Lit-parole; il secondo valuta l'argomento prima di passare; e il terzo passerà il valore indicato: questo modulo consente di passare attraverso le funzioni. Si finisce con:

make function! [ 
    ['literal evaluated referred] [ 
     foo/bar :literal evaluated :referred 
    ] 
] 

Ora del calibro di serie/iniziale è in:

array-initial: wrap array/initial [size :value] 
n: 1 
array-initial 4 does [++ n] 
+0

Ok, fantastico. Questo risolve un bug che qualcuno mi stava chiedendo su GitHub. :-) Sento che è un desiderio abbastanza comune che sarebbe bello se il dialetto delle specifiche delle funzioni ti permettesse di fare una specie di specializzazione più facilmente. Preferirei farlo con la riflessione, ma forse qualcuno potrebbe aggiungere un'altra risposta che si adatta per questo se sono annoiati ... – HostileFork

+0

Utenti GitHub, eh? – rgchris

+0

Hm ... un problema qui è che il prototipo non corrisponde alla funzione avvolta. Quindi, per esempio, il wrapper può finire con un argomento quotato quando l'originale non ce l'ha * (non è '/ valore iniziale' ... ma l'array avvolto-iniziale prende' 'value') *. C'è un modo per allineare il prototipo avvolto con l'originale? – HostileFork

0

In poche parole, si (aka me) non può raggiungere questo obiettivo senza riflettere il blocco gli argomenti della funzione che stai avvolgendo. Non c'è altro modo.

Se una funzione utilizza il modulo parola-illuminata o la forma get-word di un argomento, tale distinzione deve essere speculare nel proprio wrapper. Vedere questa risposta per la spiegazione di ciò che è la differenza tra la :foo e 'foo forma di parametro:

Why doesn't Rebol 3 honor quoted function parameters that are parenthesized?

Per @ di rgchris commento, quello che (anche noto come I) dobbiamo fare è parse the argument block. Una risposta corretta dovrebbe contenere il codice che fa questo, quindi la gente dovrebbe sentirsi libera di aggiungerla.