是否可以编写函数arity :: a -> Integer
来确定任意函数的arity,例如
> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0
答案 0 :(得分:25)
是的,它可以很容易地完成:
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
。
当然,结果可能是可以再次应用的另一个功能,等等。
听起来很愚蠢,但事实并非如此。
答案 1 :(得分:18)
使用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)
更新发现问题。您需要为多态函数指定非多态类型:
arity (foldr :: (a -> Int -> Int) -> Int -> [a] -> Int)
不知道如何解决这个问题。
Upd2 正如Sjoerd Visscher在下面评论的那样“你必须指定一个非多态的类型,因为答案取决于你选择的类型”。
答案 2 :(得分:11)
如果id
有arity 1,那么id x
不应该有arity 0吗?但是,例如,id map
与map
相同,在您的示例中将为{2}。
让以下功能相同吗?
f1 = (+)
f2 = (\x y -> x + y)
f3 x y = x + y
我认为你的“arity”概念没有明确界定......
答案 3 :(得分:3)
在Haskell中,每个“函数”只需要一个参数。看起来像“多参数”函数实际上是一个函数,它接受一个参数并返回另一个接受其余参数的函数。所以在这个意义上,所有函数都有arity 1。
答案 4 :(得分:2)
使用标准Haskell是不可能的。可以使用IncoherentInstances或类似的扩展名。
但你为什么要这样做呢?你不能向函数询问它期望多少个参数,然后使用这些知识来准确地给出它的参数数量。 (除非你正在使用Template Haskell,在这种情况下,是的,我希望它可以在编译时使用。你使用的是模板Haskell吗?)
您尝试解决的实际问题是什么?
答案 5 :(得分:1)
这个怎么样:
arity :: a -> Int
arity (b->c) = 1 + arity (c)
arity _ = 0