別の関数への個別の引数として使用されるリストを「拡張」する一般的な方法はありますか?


9

たとえばL、おそらく&rest引数からの文字列のリストがあるとします。これに対して何ができLますか?以下と同じ効果がありますか?

(concat (first L) (second L) ... (last L))

この例ではmapconcatここで機能することはわかっていますが、一般的なプロセスを探しています。)

回答:



6

あなたがしたかったことは、同じタイプのオブジェクトのシーケンスの折りたたみまたは展開のようです。apply多くの場合、実際に機能するため、この目的で使用するのは魅力的です。しかし、これはまさにこれに適したツールではありません。理由は次のとおりです。

  1. applyはメタプログラミングメカニズムですが、それだけでなく、異なるタイプのオブジェクトのシーケンスを処理でき、必ずしも2つの引数の関数を呼び出す必要がないため、タスクにとって一般的すぎます。その結果、たとえば次のような不正な動作が発生することがあります。

    (apply 'concat "baz" '("foo" "bar"))
     > "bazfoobar"
    

    しかし、直感的には、ここでは型の不一致が予想されます。

  2. apply引数をできるだけ多く処理できるようにする方法はありません。これは通常、言語の実装によって課される制限です。

  3. によって呼び出された関数は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"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.