たとえばL
、おそらく&rest
引数からの文字列のリストがあるとします。これに対して何ができL
ますか?以下と同じ効果がありますか?
(concat (first L) (second L) ... (last L))
(この例ではmapconcat
ここで機能することはわかっていますが、一般的なプロセスを探しています。)
たとえばL
、おそらく&rest
引数からの文字列のリストがあるとします。これに対して何ができL
ますか?以下と同じ効果がありますか?
(concat (first L) (second L) ... (last L))
(この例ではmapconcat
ここで機能することはわかっていますが、一般的なプロセスを探しています。)
回答:
あなたがしたかったことは、同じタイプのオブジェクトのシーケンスの折りたたみまたは展開のようです。apply
多くの場合、実際に機能するため、この目的で使用するのは魅力的です。しかし、これはまさにこれに適したツールではありません。理由は次のとおりです。
apply
はメタプログラミングメカニズムですが、それだけでなく、異なるタイプのオブジェクトのシーケンスを処理でき、必ずしも2つの引数の関数を呼び出す必要がないため、タスクにとって一般的すぎます。その結果、たとえば次のような不正な動作が発生することがあります。
(apply 'concat "baz" '("foo" "bar"))
> "bazfoobar"
しかし、直感的には、ここでは型の不一致が予想されます。
apply
引数をできるだけ多く処理できるようにする方法はありません。これは通常、言語の実装によって課される制限です。
によって呼び出された関数はapply
、この方法で渡された引数リストの参照を取得できます。これも明らかではなく、後でエラーが発生する可能性があります。
(let ((test (list 1 2 3)))
(cons
(apply (lambda (&rest x)
(prog1 (cl-reduce '+ x) (setcar x 0)))
test)
test))
;; This behaviour is undefined. Could end up both ways
> (6 1 2 3)
> (6 0 2 3)
引数リストがコピーされた場合、必要以上のメモリを節約する代償を払うことになりますが、それがコピーされない(そのまま渡される)場合、呼び出されている関数がリストを変更すると、リストが損なわれる危険があります。
したがって、それを行うためのより良い方法は、を使用することcl-reduce
です。利点は、この種のタスクを実行するように特別に設計されていることです。
(cl-reduce 'concat '("foo" "bar" "baz"))
> "foobarbaz"