혹시 누군가에게 도움이 될까 싶어 여기에 남겨둡니다. 제가 너무 앞서나가는 생각일지도 모르지만, 비슷한 걸 찾을 수가 없었어요.
문제점: 일반적으로 함수 "표현식"의 일부에 직접 접근하는 것은 불가능합니다. 여기서 "표현식"은 실제 표현식 데이터 타입이 아니라 함수이기 때문에 일반적인 표현식 조작 함수가 작동하지 않습니다.
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;
하지만 요령이 있습니다. 다음과 같이 함수를 Expression 데이터 형식으로 변환할 수 있습니다.
Parse( Char( Name Expr( function ) ) )
더 나은 방법이 있을지도 모르지만, 몇 시간 동안 연구하고 직접 테스트해 본 결과 찾을 수 없었고, 이 방법조차도 포기하기 직전에 우연히 발견한 것입니다.
어쨌든, Arg() 함수를 사용하면 해당 함수의 인수에 접근할 수 있습니다. 인수는 로컬 리스트의 존재 여부에 따라 2개 또는 3개입니다. 첫 번째 표현식 인수는 함수의 입력 리스트이고, 두 번째는 로컬 리스트(존재하는 경우)이며, 마지막은 함수 본문입니다.
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);
예를 들어, 저는 많은 디스플레이 박스를 가진 사용자 인터페이스 함수를 가지고 있는데, 대부분의 디스플레이 박스는 변수에 할당되어 있습니다. 이 함수는 자주 업데이트되는데, 시간이 지나면서 로컬 변수 목록을 관리하는 것이 번거로워집니다. 특히 변수 범위에 대한 제어력이 떨어지고 메모리 누수가 발생할 가능성이 있는 `{default local}` 방식은 사용하고 싶지 않습니다. 연관 배열이나 비슷한 방법을 사용할 수도 있겠지만, 다른 용도로 디스플레이 박스 이름 목록을 외부 리스트에 저장해 두고 있기 때문에, 이 리스트를 함수에 동적으로 로컬 변수로 주입하는 것이 더 효율적이라고 생각합니다. 물론 함수의 입력값이나 본문도 비슷한 방식으로 수정할 수 있습니다.
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";