[Gauche-devel-jp] 省略可能引数とデフォルト値

Back to archive index

Kimura Fuyuki fuyuk****@hadal*****
2003年 2月 19日 (水) 11:49:38 JST


最初に背景を明かしておきますと、これはDICT(RFC2229)のモジュールを書い
ているなかで出てきた問題です。たとえばこのプロトコルにはMATCHというコ
マンドがあるのですが、

MATCH database strategy word

このうちdatabaseとstrategyにはデフォルト値のようなものがあるので、メソッ
ドの引数を省略可能にしたいと思ったわけです。つまり、

(define-method dict-match ((self <dict>) word . args)
  (let-optionals* args ((database "*")
			(strategy "."))

のような感じです。で、これを呼び出すコマンドを書く段になって、あれ困っ
たな、と。

ちなみにRuby/DICTではmatchメソッドの引数は省略不可です。

DICT#match(database, strategy, word)

そのかわり、デフォルト値を定数として提供しています。

DICT::ALL_DATABASES
DICT::DEFAULT_MATCH_STRATEGY

PerlのNet::Dictでは、databaseだけ省略できます(別に処理するdatabaseを指
定するためのメソッドがある)。

match ( $pattern, $strategy [, @dbs] )

デフォルトのstrategyを使いたければ、"."を指定する必要があります。


At Tue, 18 Feb 2003 14:57:47 -1000 (HST),
Shiro Kawai <shiro****@lava*****> wrote:
> 
> optional引数の欠点は、前の方の引数だけ「無指定」という指定が
> できないことでしょうね。必然的に、「後のほうの引数は前の方の
> 引数が指定されて初めて意味を持つ」といった暗黙の制約がかかります。

そうですね。でも実際には前のほうのオプショナル引数を無指定にしたくなる
場合もあると思います。たとえばstring-joinでgrammerだけ指定したいとか。
Schemeではキーワードが標準ではないので、ちょっと無理をしてオプショナル
引数を使っているということでしょうか。

(脇にそれますが、マニュアルにはstring-joinのdelimのデフォルトが何であ
るか書いていません)

> どの引数も等分に出てくる可能性がある場合は、キーワード引数で
> 渡した方がすっきりするかもしれません。
> 
> (define (do-something . args)
>   (let-keywords* args ((host "www.yahoo.com")
>                        (port 80))
>     ...))
> 
> 渡すほうは引数リストを用意してやればいいので。
> 
> (define (main args)
>   (let ((do-args '()))
>     (parse-options (cdr args)
>        (("h=s" (host) (push! do-args `(,host :host)))
>         ("p=i" (port) (push! do-args `(,port :port)))))
>     (apply do-something (reverse do-args))))

暗黙の前提は「hostを指定することはよくあるがportまで指定することはめっ
たにない」だったのですが、やはりこの場合はキーワードを使ったほうがいい
ようですね。どうもキーワードはおおげさな感じがして使うのをためらってし
まうのですが

> どうしてもoptional引数でやるなら、#fが渡された場合は
> デフォルト値を使う、みたいなAPIにしておいて、次のように
> 2段構えにするとか。
> 
> (define (do-something . args)
>   (let-optionals* args ((host #f)
> 			(port #f))
>     (let ((host (or host "www.yahoo.com"))
>           (port (or port 80)))
>       ...)))
> 
> 欠点:
>   (1) 「無指定」を指定するための値は有効な値として渡せない
>   (2) do-somethingが長くなる

Common Lispはたしかこんな感じですよね(nilを置いておけば省略したのと同
じ)。あれはあれで便利だと思うのですが、Schemeには似合わない気もします。

> 一般的に使える「無指定」を指定する値があると便利そうなんですが、
> Scheme的には「無指定」値を決めた途端、その「無指定」値を
> 引数として受け渡したくなる場面が出て来るので、実際には使えない
> んですよね。

私も何度か「ここで未初期化値があれば便利なのに」とか思ったことがあるの
ですが、そう簡単に解決するわけがありませんでした。:)

-- 
木村 冬樹




Gauche-devel-jp メーリングリストの案内
Back to archive index