Come si fanno a decoratori potenti come i macro?

7

Sfondo rapido: sto progettando un linguaggio pitone che voglio essere potente come Lisp pur rimanendo facile da usare. E per "potente", intendo "flessibile ed espressivo".

Sono appena stato presentato ai decoratori di funzioni di Python e mi piacciono. Ho trovato questa domanda che suggerisce che i decoratori sono non potente come le macro Lisp. La terza risposta a questa domanda dice che la ragione per cui non lo sono è perché possono operare solo sulle funzioni.

E se potessi usare i decoratori su espressioni arbitrarie? (Nella mia lingua, le espressioni sono di prima classe, proprio come le funzioni e tutto il resto, quindi farlo sarebbe abbastanza naturale.) Ciò renderebbe i decoratori potenti quanto le macro Lisp? O dovrei usare le regole di sintassi, come Racket e Honu o qualche altra tecnica?

EDIT

Mi è stato chiesto di fornire un esempio del costrutto sintattico. Per un "decoratore di espressioni", sarebbe semplicemente un decoratore su un'espressione (dove "$ (...)" crea un oggetto espressione):

@Decorator("Params")
$(if (true):
    printf("Was true")
else:
    printf("Wasn't true"))

Inoltre, se I do deve utilizzare le regole di sintassi, come accennato in precedenza, userebbe una sintassi di corrispondenza del modello:

# Match a bool expression, a comma, and a string.
macro assert(expr:bool lit string) { e , s }:
    if (!e):
        error s
    else:
        printf("All good")

Quanto sopra corrisponderebbe a questo:

assert i == 0, "i should have been 0"

Questo è uno schizzo approssimativo, ma dovrebbe darti un'idea.

    
posta Gavin Howard 08.08.2014 - 05:52
fonte

1 risposta

8

Risposta breve: non puoi.

Non in Python o qualcosa di simile a quello che è oggi, in ogni caso. La ragione è semplice: le funzioni sono oggetti. Le espressioni non lo sono. Le espressioni descrivono le attività - l'attività di operare sugli oggetti e produrre un risultato. Mentre l'input e l'output delle espressioni sono oggetti, le espressioni stesse non lo sono. Perché non sono oggetti, non possono essere decorati.

Questa limitazione alla metaprogrammazione di Python è abbastanza cotta nel linguaggio. Non è impossibile cambiare la semantica di Python. Moduli come forbiddenfruit ti permettono di creare oggetti monkeypatch in modi che sono ufficialmente "impossibili". Moduli come MacroPy , karnickel e il MetaPython ora apparentemente defunto fornisce alcune funzionalità macro attraverso la riscrittura AST e le tecniche correlate. Tuttavia, nessuno di questi è certificato per l'uso di produzione e la maggior parte di essi viene visualizzata, supporta una o due iterazioni della lingua e quindi evapora. Le mosse double-back-flip-with-twist necessarie a farle funzionare sempre non sono sostenibili in nessun periodo di tempo, in nessuna generalità o nel contesto di "codice da cui si può dipendere".

Ci sono moduli che usano con successo l'introspezione e la riflessione per ispezionare ciò che sta accadendo attualmente in un programma. Il mio modulo dire , ad esempio, funziona bene su molte versioni di Python 2 e Python 3 e persino su implementazioni Python alternative come PyPy. Ma pochi meta-moduli Python possono effettivamente cambiare la semantica del programma. GvR è stato piuttosto resistente alle strutture di metaprogrammazione. La semantica di istruzione with , ad esempio, era vincolata allo scopo particolare di limitare la metaprogrammazione che può supportare.

Ma questo è Python così com'è oggi. Potresti immaginare il tuo linguaggio Python ++ con blocchi di codice arbitrari (il mitico lambda multi-riga, spesso menzionato ma mai visto in Python) che può essere decorato. Lambdas sono oggetti, e i blocchi di codice sono molto soggetti all'obbligo. Probabilmente non vorrai il sovraccarico di rendere l'espressione ogni in un oggetto, ma non è difficile immaginare un ambiente in cui qualsiasi espressione che è interessante da codificare in un blocco possa essere eseguita, quindi decorata.

Due linguaggi standard (cioè non Lispy) e piuttosto Pythonic che hanno lavorato per integrare la metaprogrammazione e le macro strutture avanzate sono Julia e Nim (precedentemente noto come Nimrod). Il modo in cui affrontano la rappresentazione e la trasformazione del programma sono molto potenti e sarebbero buoni punti di studio per il tuo progetto.

    
risposta data 15.08.2014 - 04:17
fonte

Leggi altre domande sui tag