传递函数作为参数,奇怪的情况

时间:2016-02-14 17:01:51

标签: haskell functional-programming

我担心它可能会变得极其狡猾,但我不知道还能在哪里问。

有一段时间我认为如果一个函数接受另一个函数作为参数,它必须在类型中明确说出它,即f :: (a -> a -> a) -> b -> c。因此我可以将g :: a -> a -> a作为第一个参数和具体类型参数作为第二个传递,但没有别的。

但我刚刚发现我可以将const :: a -> b -> a应用于(+) :: Num a => a -> a -> a。结果很奇怪(+) const :: Num (a -> b -> a) => (a -> b -> a ) -> a -> b -> a

foldr :: ( a -> b -> b) ...如何将(\b g x -> g (f x b))作为第一个参数。

foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f a bs =
   foldr (\b g x -> g (f x b)) id bs a

这里发生了什么?我甚至不知道如何调用它,所以我不能在这里搜索谷歌搜索或使用适当的标题。

我在哪里可以了解这一点?这个叫什么?它的应用和理论是什么?

2 个答案:

答案 0 :(得分:4)

关于功能类型,没有什么特别的。显然,多态函数a -> a可以用作Int -> IntString -> String。但它也可以用作(Char->Double) -> (Char->Double)。在您尝试的示例中,您基本上使用

(+) :: (a->b->a) -> (a->b->a) -> (a->b->a)

可以省略对结果的括号,所以这是

(+) :: (a->b->a) -> (a->b->a) -> a -> b -> a

如果我们提供const,我们就会

(const +) :: (a->b->a) -> a -> b -> a

到目前为止,我并没有对Num约束感到烦恼。这个约束实际上是一个问题,虽然它并非完全没有意义 - 原则上 可能为函数类型声明一个Num实例:

instance (Num r) => Num (a->r) where
  fromInteger = const . fromInteger
  f + g = \x -> f x + g x
  negate f = negate . f
  ...

然后约束Num (a->b->a)将等同于Num (b->a),而Num a仅相当于const。然后,您可以实际使用> (const + \x y -> y) 1 1 2 > (const + \x y -> x*y) 1 0 1 之类的函数:因为这是一个双参数函数,所以添加的结果将

Num

等等。

然而,仅仅因为它可以定义一个实例并不一定意味着它是一个好主意;它也可能导致奇怪的意外行为。特别是,函数的(+) const实例无法满足field axioms。实例未在标准库中定义,IMO这是好的。因此,body 实际上 在Haskell中没有任何意义。

答案 1 :(得分:1)

任何类型变量也可以用函数类型实例化。

最简单的例子给了我一个"一个ha"那一刻是要意识到:

pip_for_3 install <package name>

只是一个特例:

($) :: (a -> b) -> (a -> b)

换句话说,您可以像id :: a -> a 一样使用id作为中缀应用程序运算符:

$

您可以将ghci> negate $ 5 -5 ghci> negate `id` 5 -5 ghci> map ($ 5) [negate,(2*),(1+)] [-5,10,6] ghci> map (`id` 5) [negate,(2*),(1+)] [-5,10,6] 字面定义为($),只需将类型缩小为函数:

id

因此,总而言之,在您看到类似($) :: (a -> b) -> a -> b ($) = id 的类型变量的任何地方,您都可以选择使用类似a的函数类型来实例化它。