【问题标题】:Haskell: Function to determine the arity of functions?Haskell:函数确定函数的数量?
【发布时间】:2012-01-12 05:41:29
【问题描述】:

是否可以编写一个函数arity :: a -> Integer 来确定任意函数的元数,这样

> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0

?

【问题讨论】:

  • 我相信使用类型系统的巧妙技巧是可能的。在 haskell 中搜索可变参数或多参数函数。
  • 我认为这是一个有趣的问题,我对 max taldykin 的回答感到惊讶,但我确实想知道 - 你会用这样的功能做什么?
  • @Frerich 在提出这个问题的时候,我正在阅读 Stepanov 和 McJones 的 Elements of Programming,他们介绍了类型属性 Arity(F),它返回 F 的输入数量。我很好奇我是否可以实现他们在 Haskell 中定义的一些功能。

标签: haskell introspection arity


【解决方案1】:

是的,它可以非常非常容易地完成:

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 表示愚蠢的事实。所有 Haskell 函数都有 arity 1,因为函数可以产生函数。 a -> b -> c 只是 a -> (b -> c) 的糖。
  • 好吧,可以递归地找到函数树的深度吗?
【解决方案2】:

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 在下面评论的那样“您必须指定非多态类型,因为答案取决于您选择的类型”。

【讨论】:

  • 我们需要 OverlappingInstances 做什么?
  • @scravy,instance Arity xinstance Arity ((->) a f) 更通用。因此,如果没有扩展,GHC 无法选择这两个实例中的哪一个用于函数。 OverlappingInstances 指示 GHC a) 允许此类实例; b) 她需要选择最具体的一个。
  • 您必须指定非多态类型是有道理的,因为答案取决于您选择的类型,例如:arity (foldr :: (a -> (Int -> Int) -> Int -> Int) -> (Int -> Int) -> [a] -> Int -> Int)
  • 经过一番尝试后确定,解决方案是添加IncoherentInstances LANGUAGE pragma ;)
  • @DanBurton 我不太确定这里发生了什么,但我认为 lambda 表达式的内部表示与导致这种情况的正常函数不同。它们可能会以某种方式进行优化。例如arity (\x y z -> (x,y,z)) is 3, arity (\x y z -> x)` 是0arity (\x y z -> (x,y)2,而arity (\x y z -> (x,z)) 是令人惊讶的1。这里需要注意的是,如果左侧的所有变量都出现在右侧,那么结果是正确的,但是如果不是所有的变量都出现在右侧,那么结果就没有意义了。我们需要一些 GHC 专家:D
【解决方案3】:

如果id 的元数为1,那么id x 的元数不应该为0吗?但是,例如,id mapmap 相同,在您的示例中它的元数为 2。

以下函数的数量相同吗?

f1 = (+)
f2 = (\x y -> x + y)
f3 x y = x + y

我认为您对“a​​rity”的概念定义不明确......

【讨论】:

  • 你不能简单地说id xx的arity吗?我的意思是,如果您查看id :: a -> a,这是合理的。
  • 我对arity的定义:计算一个函数类型中没有括在括号中的->的数量。所以id x 的数量取决于x
  • 我将arity定义为您可以将参数应用于术语的次数。如果未指定参数的类型,请使用()
【解决方案4】:

在 Haskell 中,每个“函数”都只有一个参数。看起来像“多参数”的函数实际上是一个接受一个参数并返回另一个接受其余参数的函数的函数。所以从这个意义上说,所有函数的元数都为 1。

【讨论】:

    【解决方案5】:

    使用标准 Haskell 是不可能的。可以使用 IncoherentInstances 或类似的扩展。

    但是你为什么要这样做呢?你不能问一个函数它期望多少个参数,然后使用这个知识来精确地给它那个数量的参数。 (除非您使用的是 Template Haskell,在这种情况下,是的,我希望它在编译时是可能的。您使用的是 Template Haskell 吗?)

    您要解决的实际问题是什么?

    【讨论】:

    • 没有实际问题,我只是好奇。
    • 我找到了一个用例,我想将普通函数提升为等效的枚举或转换器协程。知道一个函数在返回* 类型的实例之前可以接受多少个参数会很有用。
    【解决方案6】:

    这个怎么样:

    arity :: a -> Int
    arity (b->c) = 1 + arity (c)
    arity _ = 0
    

    【讨论】:

    • GHCi 抱怨:不在范围内:“b”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-23
    • 2017-04-15
    相关资源
    最近更新 更多