Haskell:関数関数の不安を決定する機能?
-
27-10-2019 - |
質問
関数を書くことは可能ですか? arity :: a -> Integer
任意の関数の不安を決定するために、
> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0
?
解決
で簡単です 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 Sjoerd Visscherがコメントしたように、以下に「答えは選択したタイプに依存するため、非政治型を指定する必要があります」。
他のヒント
はい、それは非常に、非常に簡単に行うことができます:
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
. 。結果は、もちろん、再び適用できる別の関数などになる可能性があります。
愚かに聞こえますが、真実に他なりません。
もしも id
アリティ1がありません id x
アリティ0がありますか?しかし、たとえば、 id map
と同じです map
, 、あなたの例にはアリティ2があります。
次の機能は同じ条例を持っていますか?
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