我担心它可能会变得极其狡猾,但我不知道还能在哪里问。
有一段时间我认为如果一个函数接受另一个函数作为参数,它必须在类型中明确说出它,即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
这里发生了什么?我甚至不知道如何调用它,所以我不能在这里搜索谷歌搜索或使用适当的标题。
我在哪里可以了解这一点?这个叫什么?它的应用和理论是什么?
答案 0 :(得分:4)
关于功能类型,没有什么特别的。显然,多态函数a -> a
可以用作Int -> Int
或String -> 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
的函数类型来实例化它。