yunomuのブログ

酒とゲームと上から目線

Haskellで可変長引数

可変長引数を作りたかったわけではないんだけど、というか何がしたかったんだかよく覚えていないんだけど、こういうのを作った。

class Test a where
    test :: a -> Int 
    test = const 0

instance Test a => Test (b -> a) where
    test f = 1 + test (f undefined)

instance Test Int 

Test型クラス。

> let c = undefined :: Int
> test c
0
> let f = undefined :: Int -> Int
> test f
1
> let g = undefined :: Int -> Int -> Int
> test g
2

test関数に与えた関数の引数の数を数えられます。
ただし、与える関数の戻り値の型がTestのインスタンスになっていないと使えません。

これ、なんとなく面白くはあるんだけど、何の意味があるんだ。使い所もよくわかんなくなっちゃったなぁなんて思っていたんですが、printfがこの仕組で作られていました。
http://hackage.haskell.org/package/base-4.6.0.1/docs/Text-Printf.html
うわあああこれprintfじゃないか!
あとQuickCheckのpropというかTestableクラスも思いっきりこの仕組で実装されていました。
http://hackage.haskell.org/package/hspec-1.7.2.1/docs/Test-Hspec-QuickCheck.html
http://hackage.haskell.org/package/QuickCheck-2.6/docs/Test-QuickCheck-Property.html#t:Testable
誰だ使い所無いとか言ったやつ。

特にQuickCheckなんて最近も使ってるし、なんで疑問に思わなかったのか。これ作った人頭いいな。

まあそれはいいとして、

class Arg a where
    f :: c -> a

みたいな型クラスを定義して、

instance Arg a => Arg (b -> a) where
    f = ...

みたいなインスタンスを作ると可変長引数関数が作れるみたいです。
(b -> a)がArgのインスタンスなら(d -> b -> a)というか(d -> (b -> a))もArgのインスタンスになるので。