Haskell で可変長引数を扱う方法

一口に可変長引数と言っても色々あります。限られた範囲でのオプション引数が欲しいこともありますし、多相的な本物の可変長引数が欲しいこともあります。また、可変長引数を型安全に使いたいのか、型安全性を無視してでも使いたいのか、という話もあります。このようにどういうことをしたいかによって、可変長引数を実現するために採用するべき手段は異なってきます。ここにある程度情報をまとめておきましたので、是非参考にしてみてください。
20
shelarcy(しぇらーしぃ) @shelarcy

「あなたの求めている可変長引数は、(単相型の) variadic のことですか、それとも polyvariadic のことですか?」

2011-12-01 13:14:41

Haskell での可変長引数の実現方法

Haskell で可変長引数というと、日本語での Haskell 界隈では QuickCheck や Text.Printf のように型クラスを使う方法が良く知られているようです。 http://itpro.nikkeibp.co.jp/article/COLUMN/20080304/295346/ http://haskell.g.hatena.ne.jp/illillli/20080313/1205428973

ただ型クラスを使う方法は、定義が面倒なわりに型安全性を壊してしまいがちです。なので、どうしても型クラスが必要だったり、型クラスでないと実現できないのでなければ、別の方法を使うことをお勧めします。

shelarcy(しぇらーしぃ) @shelarcy

@shanonnstream 正確には Haskell で可変長引数を実現する方法としては「Text.Printf のように型クラスを使う方法」が有名だけど、型クラスを利用した可変長引数は(Text.Printf のように)型安全でない可能性があるのでお勧めできないですね。

2010-11-02 12:02:47
shelarcy(しぇらーしぃ) @shelarcy

@shanonnstream 型クラス以外での可変長引数のやり方については、手前味噌ですがこのスライドにまとめてあります。 http://freett.com/shelarcy/log/2008/diary_12.html#language_talks

2010-11-02 12:06:25
shelarcy(しぇらーしぃ) @shelarcy

@shanonnstream スライド中に説明のないリストを使った可変長引数のやり方については、やはり手前味噌ですが連載のこの辺に書いてあります。 http://itpro.nikkeibp.co.jp/article/COLUMN/20071204/288630/

2010-11-02 12:08:25
shelarcy(しぇらーしぃ) @shelarcy

@shanonnstream このリストを使ったやり方は、Monoid クラスのインスタンスとなる型に一般化できますよね。それが前に話題になった polyToMonoid [http://bit.ly/dfqdK9 ] の話です。 http://bit.ly/ajqmvF

2010-11-02 12:13:09

型安全な printf や polyToMonoid の話は、後の方にまとめてあります。

オプション引数とキーワード引数(ラベル付き引数)

引数のデフォルト値

茶蔦 @tyatsuta

HaskellでDSL設計するとき、デフォルト引数の概念はどうやって実装したらいいのだろう。関数の引数は固定長だから無理?

2011-03-25 13:48:40
shelarcy(しぇらーしぃ) @shelarcy

@tyatsuta 関数の引数を Foo a b = Foo {bar:: a, baz ::b } という型にまとめておいて、Foo のデフォルト値を defaultFoo として用意しておけば、フィールドの更新を使うことで任意の引数だけを書き換えて関数に渡すことができますね。

2011-03-25 14:45:58
shelarcy(しぇらーしぃ) @shelarcy

@tyatsuta 一引数なら、turnWithDirection のように Direction 型を必要とする関数と、turn val = turnWithDirection val Right のように Direction 型を必要しない関数を作って使い分けるのが普通ですね

2011-03-25 15:08:56

フィールドの更新をつかって、オプション引数やキーワード引数を実現

shelarcy(しぇらーしぃ) @shelarcy

@mr_konn どんなことがやりたいのかわかりませんが、可変長引数を実現したいならもう一つ、「名前付きフィールドを持つデータ型を作って、フィールド更新で必要なだけパラメータを書き換える(つまり、フィールド更新をキーワード引数のように扱う)」という方法もありますよ。

2009-09-18 00:14:27
shelarcy(しぇらーしぃ) @shelarcy

@mr_konn これはCabalのDistribution.Simpleの UserHook [http://j.mp/fsplP] やSystem.Processの createProcess [http://j.mp/10ZvuG] などでも使われている割と定番の方法です。

2009-09-18 00:16:00
shelarcy(しぇらーしぃ) @shelarcy

@keigoi あっ、そういえばフィールドラベルを持つデータ型を使い、「デフォルト値として用意した変数(defaultConfig とか)に対するフィールドの更新」を、オプション引数として利用するテクニックってあまり使いませんか?

2010-12-23 16:37:18
shelarcy(しぇらーしぃ) @shelarcy

@keigoi Cabal で使っているのを見て、真似して使っている人はそれなりにいると思うのですが……例えば criterion も、フィールドラベルを使ったフィールドの更新をオプション引数として活用する形になってますね。 http://bit.ly/fC7G0w

2010-12-23 16:44:41

zipN や zipWithN は Applicative で実現できる

Hideyuki Tanaka @tanakh

ZipListはMonadにできないんで、使い道がわからん。MonadじゃないApplivativeなんて、価値半減な気がする。

2011-07-21 05:36:28
shelarcy(しぇらーしぃ) @shelarcy

@tanakh ドキュメントに書いてある通り、Applicative の論文に例として出てくる zipWithN 関数を作るためのものですよ。 http://j.mp/nXPlKT

2011-07-21 05:58:20
shelarcy(しぇらーしぃ) @shelarcy

@tanakh ghci> let xs = ZipList [1..10] ghci> getZipList $ (,) <$> xs <*> xs ghci> getZipList $ (,,) <$> xs <*> xs <*> xs

2011-07-21 05:58:50

polyvariadic

Hackage @Hackage

polyToMonoid 0.1, added by KevinJardine: Polyvariadic functions mapping to a given monoid http://bit.ly/avXKtS

2010-10-14 19:48:57