arity :: a -> Integer
任意の関数のアリティを決定する関数を書くことは可能ですか?
> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0
?
arity :: a -> Integer
任意の関数のアリティを決定する関数を書くことは可能ですか?
> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0
?
はい、非常に簡単に実行できます。
arity :: (a -> b) -> Int
arity = const 1
理由: 関数の場合、正確に 1 つの引数に適用できます。haskell 構文では、0 個、2 個、またはそれ以上の引数をそのままの形で適用することはできないことに注意f a b
し(f a) b
てf applied to a and b
ください(f applied to a) applied to b
。もちろん、その結果は、再度適用できる別の関数になる可能性があります。
ばかげているように聞こえますが、真実に他なりません。
それは簡単OverlappingInstances
です:
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
class Arity f where
arity :: f -> Int
instance Arity x where
arity _ = 0
instance Arity f => Arity ((->) a f) where
arity f = 1 + arity (f undefined)
Upd問題が見つかりました。ポリモーフィック関数には非ポリモーフィック タイプを指定する必要があります。
arity (foldr :: (a -> Int -> Int) -> Int -> [a] -> Int)
これを解決する方法はまだわかりません。
Upd2 as Sjoerd Visscher が以下にコメントしたように、「答えは選択したタイプに依存するため、非ポリモーフィック タイプを指定する必要があります」。
id
アリティが 1 の場合、id x
アリティが 0 であってはなりませんか? しかし、たとえば、あなたの例ではアリティ2を持つid map
と同じです。map
次の関数のアリティは同じですか?
f1 = (+)
f2 = (\x y -> x + y)
f3 x y = x + y
「アリティ」の概念が明確に定義されていないと思います...
Haskell では、すべての「関数」は厳密に 1 つの引数を取ります。「複数引数」関数のように見えるものは、実際には 1 つの引数を取り、残りの引数を取る別の関数を返す関数です。その意味で、すべての関数のアリティは 1 です。
標準の Haskell では不可能です。IncoherentInstances または同様の拡張機能を使用すると、可能になる場合があります。
しかし、なぜこれをしたいのですか?関数に期待する引数の数を尋ね、この知識を使用して正確にその数の引数を与えることはできません。(テンプレート Haskell を使用している場合を除きます。その場合は、はい、コンパイル時に可能であると思います。テンプレート Haskell を使用していますか?)
あなたが解決しようとしている実際の問題は何ですか?
これはどう:
arity :: a -> Int
arity (b->c) = 1 + arity (c)
arity _ = 0