GNU Octave 평가(Evaluation)
GNU Octave 평가(Evaluation)
Octave는 "표현식을 평가한다"는 개념이 특히 유연해요. 함수 이름을 문자열로 갖고 호출하거나, 다른 함수의 문맥(context)에서 표현식을 평가할 수 있거든요. 함수를 값처럼 다뤄야 할 때 필요한 기능들이에요.
출처: GNU Octave 평가
본문
이름으로 함수 호출하기: feval
feval 함수는 함수 이름이 담긴 문자열(또는 함수 핸들)로 그 함수를 호출할 수 있게 해줘요. 사용자가 제공한 함수를 호출해야 하는 함수를 작성할 때 특히 유용하죠.
feval ("acos", -1) # ⇒ 3.1416
feval은 첫 번째 인자로 호출할 함수 이름을 받고, 나머지 인자는 그 함수에 전달돼요. 함수 핸들(예: @exp)과도 함께 쓸 수 있어요. 문자열 안의 함수 이름을 호출하는 유일한 수단이었던 시절도 있었지만, 지금은 함수 핸들이 더 깔끔한 문법을 제공해서 선호돼요.
f = @exp;
feval (f, 1) # ⇒ 2.7183
f (1) # ⇒ 2.7183 (같은 결과)
f가 함수 핸들인지, 문자열 함수 이름인지, 인라인 함수인지 미리 알 수 없다면 feval을 쓰면 돼요. 비슷한 함수로 스크립트 파일을 실행하는 run이 있어요. 로드 경로에 없는 스크립트는 run script로 실행할 수 있어요.
뉴턴 방법으로 사용자 함수의 근을 찾는 간단한 예시를 볼게요. feval (fname, x)로 함수를 호출하는 방식이 핵심이에요.
function result = newtroot (fname, x)
delta = tol = sqrt (eps);
maxit = 200;
fx = feval (fname, x);
for i = 1:maxit
if (abs (fx) < tol)
result = x;
return;
else
fx_new = feval (fname, x + delta);
deriv = (fx_new - fx) / delta;
x = x - fx / deriv;
fx = fx_new;
endif
endfor
result = x;
endfunction
다른 문맥에서 평가하기: evalin / assignin
표현식을 평가하기 전에 그 안에 쓰인 변수의 값을 대입해야 하는데, 이 값은 심볼 테이블에 저장돼 있어요. 인터프리터가 새 함수를 시작하면 현재 심볼 테이블을 저장하고, 함수 파라미터와 nargin 같은 미리 정의된 변수로 초기화된 새 테이블을 만들어요. 함수 안의 표현식은 이 새 심볼 테이블을 사용하죠.
가끔은 함수를 호출하면 호출자(caller) 자신의 문맥에서 변수를 수정하도록 만들고 싶을 때가 있어요. 이는 C의 포인터처럼 "이름으로 넘기는(pass-by-name)" 스타일 함수를 가능하게 해요.
evalin (context, try)—context("caller" 또는 "base")에서 표현식을 평가해요.eval과 같지만 평가 문맥이 다르죠.assignin (context, varname, value)— "base" 또는 "caller" 문맥의varname에value를 대입해요.
예를 들어 함수가 호출자 문맥의 변수 값을 읽어 저장 파일을 만드는 상황을 생각해 볼게요.
function save (file, name1, name2)
f = open_save_file (file);
save_var (f, name1, evalin ("caller", name1));
save_var (f, name2, evalin ("caller", name2));
endfunction
여기서 "caller"는 데이터를 만든 함수이고, name1은 "x"라는 문자열이라 evalin ("caller", name1)은 곧 x의 값으로 평가돼요. 반대로 load는 assignin ("caller", name, val)로 값을 호출자 문맥에 되돌려줘요.
이런 함수는 실제로는 드물게 쓰여요. 대표적인 예가 fail ('code', 'pattern')으로, 코드를 caller 문맥에서 평가하고 그 오류 메시지가 주어진 패턴과 일치하는지 확인해요. save/load 같은 건 C++로 작성되어 모든 변수가 이미 "caller" 문맥에 있어서 evalin이 필요 없어요.
더 알아보기
- Expressions — 함수 호출과 인덱싱
- Functions and Scripts — 함수 정의
- Errors and Warnings — 오류 처리