基本的なリスト操作を実装しましょう。
関数型言語では、lengthやmap、reduceのようなリスト操作がよく使われます。既存の関数を使わずに、一連の基本的なリスト操作を実装してみましょう。
実装する操作の正確な数や名前は、既存の名前との衝突を避けるため、トラックによって異なります。ただし、一般的には次のような操作を実装します。
append(2つのリストが与えられたとき、2つ目のリストのすべての要素を1つ目のリストの末尾に追加します)。concatenate(一連のリストが与えられたとき、すべてのリストの要素を1つの平坦なリストにまとめます)。filter(述語とリストが与えられたとき、predicate(item)がTrueになるすべての要素のリストを返します)。length(リストが与えられたとき、その中にある要素の総数を返します)。map(関数とリストが与えられたとき、すべての要素にfunction(item)を適用した結果のリストを返します)。foldl(関数・リスト・初期アキュムレーターが与えられたとき、各要素を左からアキュムレーターに畳み込みます(reduce))。foldr(関数・リスト・初期アキュムレーターが与えられたとき、各要素を右からアキュムレーターに畳み込みます(reduce))。reverse(リストが与えられたとき、元の要素をすべて逆順に並べたリストを返します)。なお、畳み込み関数(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」は、2つの要素からなる配列{argList body}で、本質的には無名のproc(または「lambda」)です。
applyコマンドはその無名のprocを呼び出し、必要な引数を渡します。
例として、次はどれも同じ意味です。
# 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を使うと、コードのブロックを渡しやすくなります。