apply — 익명 함수 적용하기

apply — 익명 함수 적용하기

이름 없는 함수, 즉 익명 함수를 즉석에서 정의해 그 자리에서 호출하고 싶을 때가 있어요. apply가 바로 그런 용도의 명령입니다. proc으로 프로시저를 만들면 이름을 지어야 하는데, 이름이 필요 없는 일회성 함수라면 apply가 더 알맞아요.

출처: apply manual page

본문

apply func ?arg1 arg2 ...?

apply 명령은 함수 func를 인자 *arg1 arg2 ...*에 적용하고 그 결과를 리턴합니다.

함수 func는 두 요소 리스트 {args body} 또는 세 요소 리스트 {args body namespace} 형태예요(마치 list 명령으로 만든 것처럼). 첫 번째 요소 argsfunc의 형식 인자를 지정합니다. 형식 인자 args의 명세는 proc 명령과 공유되며, 해당 매뉴얼 페이지에 자세히 설명돼 있어요.

body의 내용은 형식 인자에 해당하는 지역 변수들이 실제 인자 *arg1 arg2 ...*의 값으로 채워진 뒤 Tcl 인터프리터에 의해 실행됩니다. body가 실행되는 동안 변수 이름은 보통 지역 변수를 가리키며, 이 지역 변수들은 참조될 때 자동으로 생성되고 apply가 리턴할 때 삭제돼요. 함수의 인자마다 지역 변수 하나가 자동으로 만들어집니다. 전역 변수는 global 명령이나 upvar 명령으로만 접근할 수 있어요. 네임스페이스 변수는 variable 명령이나 upvar 명령으로만 접근할 수 있습니다.

apply의 호출은 Tcl 평가 스택(즉 uplevel을 통해 접근하는 프레임 스택)에 호출 프레임을 추가합니다. body의 실행은 이 호출 프레임 안에서, namespace로 지정된 네임스페이스에서 진행돼요. namespace가 지정되지 않았다면 전역 네임스페이스에서 실행됩니다. namespace가 주어지면 그 이름이 "::"로 시작하지 않더라도 전역 네임스페이스에 상대적으로 해석돼요.

apply의 의미는 다음과 같이도 표현할 수 있습니다:

proc apply {fun args} {
    set len [llength $fun]
    if {($len < 2) || ($len > 3)} {
         error "can't interpret \"$fun\" as anonymous function"
    }
    lassign $fun argList body ns
    set name ::$ns::[getGloballyUniqueName]
    set body0 {
         rename [lindex [info level 0] 0] {}
    }
    proc $name $argList ${body0}$body
    set code [catch {uplevel 1 $name $args} res opt]
    return -options $opt $res
}

예시

목록의 각 요소에 변환을 적용하는 간단한 일반 명령을 만들어 봅니다.

proc map {lambda list} {
    set result {}
    foreach item $list {
        lappend result [apply $lambda $item]
    }
    return $result
}
map {x {return [string length $x]:$x}} {a bb ccc dddd}
      → 1:a 2:bb 3:ccc 4:dddd
map {x {expr {$x**2 + 3*$x - 2}}} {-4 -3 -2 -1 0 1 2 3 4}
      → 2 -2 -4 -4 -2 2 8 16 26

applytrace 명령에서 쓸 콜백을 정의할 때도 유용해요.

set vbl "123abc"
trace add variable vbl write {apply {{v1 v2 op} {
    upvar 1 $v1 v
    puts "updated variable to \"$v\""
}}}
set vbl 123
set vbl abc

더 알아보기

  • proc, uplevel — 프로시저 정의와 호출 프레임
  • 키워드: anonymous function, argument, lambda, procedure