Posted 2021-06-19 18:16:27 GMT
InfoQ: Swift 5.4が複数の可変数引数、リザルトビルダなどをサポートの記事を読んで、lSwiftがCommon Lispでいう可変長なキーワード引数をサポートするようなのですが、Common Lispだとどんなことになるか真似してみることにしました。
;// The third parameter does not require a label because the second isn't variadic.
;func splitVarargs(a: Int..., b: Int, _ c: Int...) { }
;splitVarargs(a: 1, 2, 3, b: 4, 5, 6, 7)
;// a is [1, 2, 3], b is 4, c is [5, 6, 7].
一見して混乱の元に感じるのですが、Swiftだと便利な状況なのでしょう。
Common Lispだとキーワード引数は可変にすることはできません。
ただ下記のようにマクロのラムダ引数であればリストにできるので機能的に同等のものは書けるでしょう。
(defmacro split-varargs (&key ((:a (&rest a) nil)) b ((:c (&rest c) nil)))
`(list ,@a ,b ,@c))(split-varargs :a (1 2 3) :b 4 :c (5 6 7))
→ (1 2 3 4 5 6 7)
(split-varargs :b 4 :a (1 2 3) :c (5 6 7))
→ (1 2 3 4 5 6 7)
;splitVarargs(b: 4)
;// a is [], b is 4, c is [].
(split-varargs :b 4)
→ (4)twoVarargs()
(two-varargs)
→ nil
寧ろ括弧でグルーピングした方が読み易いのでは
固定長の場合、ラベル(キーワード)を省略できるそうなのですが、混乱しそうな機能をどんどん盛り込んでる気がしてならない……。
;// The third parameter does not require a label because the second isn't variadic.
;func splitVarargs(a: Int..., b: Int, _ c: Int...) { }
;splitVarargs(a: 1, 2, 3, b: 4, 5, 6, 7)
;// a is [1, 2, 3], b is 4, c is [5, 6, 7].
;splitVarargs(a: 1, 2, 3, b: 4, 5, 6, 7)
(defmacro split-varargs (&key ((:a (&rest a) nil)) b ((:c (&rest c) nil)))
`(list ,@a ,b ,@c))(split-varargs :a (1 2 3) :b 4 :c (5 6 7))
→ (1 2 3 4 5 6 7)
(split-varargs :b 4 :a (1 2 3) :c (5 6 7))
→ (1 2 3 4 5 6 7)
;splitVarargs(b: 4)
;// a is [], b is 4, c is [].
(split-varargs :b 4)
→ (4)
固定長の方にはデフォルト値を与えることが可能
;// Note the third parameter doesn't need a label even though the second has a default expression. This
;// is consistent with the current behavior, which allows a variadic parameter followed by a labeled,
;// defaulted parameter, followed by an unlabeled required parameter.
;func varargsSplitByDefaultedParam(_ a: Int..., b: Int = 42, _ c: Int...) { }
;func varargsSplitByDefaultedParam(_ a: Int..., b: Int = 42, _ c: Int...) { }
(defmacro varargs-split-by-defaulted-param (&key ((:a (&rest a) nil)) (b 42) ((:c (&rest c) nil)))
`(list ,@a ,b ,@c));varargsSplitByDefaultedParam(1, 2, 3, b: 4, 5, 6, 7)
;// a is [1, 2, 3], b is 4, c is [5, 6, 7].
(varargs-split-by-defaulted-param :a (1 2 3) :b 4 :c (5 6 7))
→ (1 2 3 4 5 6 7)
;varargsSplitByDefaultedParam(b: 4, 5, 6, 7)
;// a is [], b is 4, c is [5, 6, 7].
(varargs-split-by-defaulted-param :b 4 :c (5 6 7))
→ (4 5 6 7)
;varargsSplitByDefaultedParam(1, 2, 3)
(varargs-split-by-defaulted-param :a (1 2 3))
→ (1 2 3 42)
;twoVarargs(1, 2, 3)
NG (two-varargs 1 2 3)
上記の場合、(two-varargs :a 1 2 3)
を(two-varargs 1 2 3)
と書けたりするということなのですが、Common Lispの場合、引数をリストで受け取って全部自前で処理すれば可能ですが、組み込みの機能では無理です。
しかし、これも混乱の元になる機能のような……。
キーワード引数で&rest
というのはCommon Lispでも実際に使っているのを目にしたことはありませんが、多分、見掛けが関数呼び出しに見えてしまうので避けられるのでしょう。
■
HTML generated by 3bmd in LispWorks 7.0.0