问题
Is it possible to write a function arity :: a -> Integer
to determine the arity of arbitrary functions, such that
> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0
?
回答1:
It's easy with 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 Found problem. You need to specify non-polymorphic type for polymorphic functions:
arity (foldr :: (a -> Int -> Int) -> Int -> [a] -> Int)
Don't know how to solve this yet.
Upd2 as Sjoerd Visscher commented below "you have to specify a non-polymorphic type, as the answer depends on which type you choose".
回答2:
Yes, it can be done very, very easily:
arity :: (a -> b) -> Int
arity = const 1
Rationale: If it is a function, you can apply it to exactly 1 argument. Note that haskell syntax makes it impossible to apply to 0, 2 or more arguments as f a b
is really (f a) b
, i.e. not f applied to a and b
, but (f applied to a) applied to b
.
The result may, of course, be another function that can be applied again, and so forth.
Sounds stupid, but is nothing but the truth.
回答3:
If id
has arity 1, shouldn't id x
have arity 0? But, for example, id map
is identical to map
, which would has arity 2 in your example.
Have the following functions the same arity?
f1 = (+)
f2 = (\x y -> x + y)
f3 x y = x + y
I think your notion of "arity" is not well defined...
回答4:
In Haskell, every "function" takes exactly one argument. What looks like a "multi-argument" function is actually a function that takes one argument and returns another function which takes the rest of the arguments. So in that sense all functions have arity 1.
回答5:
It's not possible with standard Haskell. It may be possible using the IncoherentInstances or similar extension.
But why do you want to do this? You can't ask a function how many arguments it expects and then use this knowledge to give it precisely that number of arguments. (Unless you're using Template Haskell, in which case, yes, I expect it is possible at compile time. Are you using Template Haskell?)
What's your actual problem that you're trying to solve?
回答6:
How about this:
arity :: a -> Int
arity (b->c) = 1 + arity (c)
arity _ = 0
来源:https://stackoverflow.com/questions/8369114/haskell-function-to-determine-the-arity-of-functions