Lascio questo qui nel caso possa essere utile a qualcuno. Forse sto inventando tutto, ma non sono riuscito a trovare nulla di simile.
Problema: in generale non è possibile accedere direttamente alle parti di una funzione "espressione", "espressione" tra virgolette perché non è propriamente un tipo di dati di tipo Expression ma una funzione, quindi le normali funzioni di manipolazione delle espressioni non funzionano:
f = Function( { x }, Return( x ) );
Show( Type( Name Expr(f) ), N Arg( Name Expr(f) ) );
// output:
Type(Name Expr(f)) = "Function";
N Arg(Name Expr(f)) = 0;
Tuttavia, c'è un trucco: è possibile trasformare una funzione in un tipo di dati Expression utilizzando:
Parse( Char( Name Expr( function ) ) )
Forse esiste un modo più elegante, ma dopo ore di ricerca e prove personali non sono riuscito a trovarlo, e anche questo metodo l'ho scoperto quasi per caso, poco prima di arrendermi.
Comunque, è possibile accedere ai suoi argomenti tramite Arg(). Ne ha 2 o 3, a seconda della presenza dell'elenco delle variabili locali. Il primo argomento dell'espressione è l'elenco degli input della funzione, il secondo è l'elenco delle variabili locali, se presente, e l'ultimo è il corpo della funzione.
f = Function( { greeting, planet }, { output },
output = Concat( greeting, " ", planet, "!");
Return( output )
);
f_as_expr = Parse( Char( Name Expr( f ) ) );
Show( Arg( f_as_expr, 1 ), Arg( f_as_expr, 2 ), Arg( f_as_expr, 3 ) )
// output:
Arg(f_as_expr, 1) = {greeting, planet};
Arg(f_as_expr, 2) = {output};
Arg(f_as_expr, 3) = output = greeting || " " || planet || "!"; Return(output);
Ad esempio, ho una funzione di interfaccia utente con molte caselle di visualizzazione e la maggior parte di esse è assegnata a una variabile. Aggiorno spesso questa lista, quindi dopo un po' la gestione delle variabili locali diventa problematica, poiché non voglio usare `{default local}` a causa del minore controllo sull'ambito delle variabili e del rischio di perdite di memoria. So che potrei usare un array associativo o un approccio simile, ma poiché gestisco anche la lista dei nomi delle caselle di visualizzazione in una lista esterna per altri scopi, posso iniettarla dinamicamente nella funzione come variabile locale. Naturalmente, è possibile modificare anche gli input e il corpo della funzione in modo simile.
Names Default To Here(1);
// f must be passed as Name Expr(f), add_locals as list of strings
inject_locals = Function( { f, add_locals }, { f_as_expr, cur_locals, new_locals },
f_as_expr = Parse( Char( Name Expr( f ) ) );
add_locals = Transform Each( {al}, add_locals, Parse(al) );
Match( N Arg( f_as_expr ),
2,
Insert Into( f_as_expr, add_locals, 2 ),
3,
cur_locals = Arg( f_as_expr, 2);
new_locals = cur_locals || add_locals;
Substitute Into( f_as_expr, cur_locals, new_locals ),
Throw( "inject_local error: unexpected function structure.")
);
Return( Eval( Name Expr( f_as_expr ) ) )
);
// simplified example of use
f = Function( {}, { output },
greeting = "Hello";
planet = "Earth";
output = Concat( greeting, " ", planet, "!" )
);
// globals to show that f internals remain local after injection
greeting = "Goodbye";
planet = "Mars";
additional_locals = { "greeting", "planet" };
f_injected = inject_locals( Name Expr(f), additional_locals );
Show( f, f_injected, f_injected(), greeting, planet )
// output:
f = Function({},{output},greeting = "Hello"; planet = "Earth"; output = greeting || " " || planet || "!");
f_injected = Function({},{output, greeting, planet},greeting = "Hello"; planet = "Earth"; output = greeting || " " || planet || "!");
f_injected() = "Hello Earth!";
greeting = "Goodbye";
planet = "Mars";