Come viene implementato il pass-by-name completo?

3

Se consideri Scala e il suo pass-by-name puoi (se non sbaglio) comprimere l'argomento a lambda e passarlo per valore alla funzione. Internamente la funzione userebbe il parametro pass-by-name come lambda.

Tuttavia in Algol puoi modificare il parametro (quindi è possibile scrivere swap per esempio).

La mia domanda è: come viene implementato il pass-by-name completo?

    
posta greenoldman 08.06.2016 - 20:06
fonte

1 risposta

4

Ci sono due possibili implementazioni. La prima è la sostituzione testuale, I.e. la funzione chiamata viene espansa in linea con i riferimenti ai suoi parametri sostituiti con il codice che si fornisce. Questa è fondamentalmente una forma di macro e soffre di molti dei problemi inerenti a questo, in particolare che una funzione non può essere resa ricorsiva quando definita in questo modo.

L'altro è usare un paio di "thunk", cioè. codice generato che sostituisce le operazioni di lettura e scrittura del parametro. Puoi simularlo in un linguaggio OOP definendo un'interfaccia, ad es.

public interface CallByNameArg<T>
{
    void set (T value);
    T get();
}

Quindi una funzione usa quei metodi quando vuole accedere ai suoi argomenti, ad es. una funzione in una lingua chiamata per nome simile alla seguente:

int sum (int index, int start, int end, int value) // call-by-name
{
    int r = 0;
    for (index = start; index < end; index ++) r += value;
    return r;
}

diventa

int sum (CallByName<int> index, CallByName<int> start, CallByName<int> end, CallByName<int> value)
{
    int r = 0;
    for (index.set (start.get ()); index.get() < end.get();
         index.set (index.get () + 1))
            r += value.get();
   return r;
}

e un sito di chiamata:

int a[] = ....;
int i;
int s = sum(i, 0, a.length; a[i]);

diventa (assumendo una lingua con le giuste chiusure, quindi non Java anche se ho usato la sintassi simile a Java):

int s = sum (new CallByNameArg {
    void set (int value) { i = value; }
    int get () { return i; } }, new CallByNameArg {
    void set (int value) { throw NotModifiable; }
    int get () { return 0; } } new CallByNameArg {
    void set (int value) { throw NotModifiable; }
    int get () { return a.length; } }, new CallByNameArg {
    void set (int value) { a[i] = value; }
    int get () { return a[i]; } });

Se non hai chiusure effettive nella tua lingua, puoi simularle spostando variabili modificabili (in questo caso i e a) in un oggetto e definendo le istanze CallByNameArg come classi interne o simili.

Spero che ciò lo renda un po 'più chiaro.

    
risposta data 08.06.2016 - 23:34
fonte

Leggi altre domande sui tag