기본적인 배열 연산을 구현해요.
함수형 언어에서는 length, map, reduce 같은 배열 연산을 아주 흔하게 사용해요.
기존 함수를 사용하지 않고, 일련의 기본적인 배열 연산을 직접 구현해요.
구현할 연산의 정확한 개수와 이름은 기존 이름과의 충돌을 피하기 위해 track마다 달라요. 하지만 일반적으로 구현하게 될 연산은 다음과 같아요:
append (주어진 두 배열에서, 두 번째 배열의 모든 항목을 첫 번째 배열의 끝에 추가해요);concatenate (주어진 여러 배열의 모든 항목을 하나로 평탄화한 배열로 합쳐요);filter (주어진 술어와 배열에서, predicate(item)이 True인 모든 항목의 배열을 반환해요);length (주어진 배열의 전체 항목 개수를 반환해요);map (주어진 함수와 배열에서, 모든 항목에 function(item)을 적용한 결과의 배열을 반환해요);foldl (주어진 함수, 배열, 초기 누적자를 받아, 왼쪽부터 각 항목을 누적자에 접어 넣어요(누적해요));foldr (주어진 함수, 배열, 초기 누적자를 받아, 오른쪽부터 각 항목을 누적자에 접어 넣어요(누적해요));reverse (주어진 배열의 모든 원래 항목을 뒤집힌 순서로 담은 배열을 반환해요).참고로, fold 함수(foldl, foldr)에 인자가 전달되는 순서는 중요해요.
apply 명령테스트 케이스가 혼란스러워 보일 수 있어요. 다음을 구현해야 해요:
set myList {alpha beta gamma delta}
listOps::filter $myList {{word} {expr {[string length $word] == 4}}
그 마지막 인자에는 왜 이렇게 중괄호가 많을까요?
proc 명령이 어떻게 정의되는지 떠올려 봐요:
proc procName argList body
Tcl에는 apply 명령이 있어요:
apply func ?arg1 arg2 ...?
여기서 "func"는 본질적으로 익명 프로시저(또는 "람다")인 두 원소짜리 리스트 {argList body}예요.
apply 명령은 그 익명 프로시저를 호출하면서 필요한 인자들을 전달해요.
예를 들어, 다음은 서로 같아요:
# using proc
proc myReverse {str} {return [string reverse $str]}
puts [myReverse "Hello, World!"]
# using apply
puts [apply {{str} {string reverse $str}} "Hello, World!"]
# or, store the func in a variable
set func {{str} {string reverse $str}}
puts [apply $func "Hello, World!"]
apply를 사용하면 코드 블록을 주고받기가 더 간단해져요.
재귀를 실용적으로 소개하는 내용을 즐기면서, 배열 연산의 명령형 및 함수형 대안을 살펴보고, 꼬리 호출 재귀와 누산기 함수까지 깊이 파고들어요.