了解Haskell类型签名

时间:2014-03-11 21:38:10

标签: haskell types type-signature

我正在自学Haskell,我想知道以下类型的签名:

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

我应该如何解释(没有双关语)?

一个半相似的结果也证明是令人费解的:

Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Prelude>

3 个答案:

答案 0 :(得分:30)

我将以map开头。 map函数将操作应用于列表中的每个元素。如果我有

add3 :: Int -> Int
add3 x = x + 3

然后我可以使用Int将其应用于map的整个列表:

> map add3 [1, 2, 3, 4]
[4, 5, 6, 7]

所以,如果你看一下类型签名

map :: (a -> b) -> [a] -> [b]

您会看到第一个参数是(a -> b),它只是一个带a并返回b的函数。第二个参数是[a],它是类型a的值列表,以及返回类型[b],类型b的值列表。所以用简单的英语,map函数将一个函数应用于值列表中的每个元素,然后将这些值作为列表返回。

这是使map成为高阶函数的原因,它将函数作为参数并对其进行处理。查看map的另一种方法是在类型签名中添加一些括号以使其成为

map :: (a -> b) -> ([a] -> [b])

因此,您也可以将其视为将函数从a转换为b到从[a][b]的函数的函数。


函数($)的类型为

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

一样使用
> add3 $ 1 + 1
5

所有这一切都取决于正确的内容,在本例中为1 + 1,并将其传递给 left 上的函数,这里add3。为什么这很重要?它有一个方便的 fixity 或运算符优先级,使其等同于

> add3 (1 + 1)

因此无论如何,在传递给左边之前,基本上包含在括号中。这使得将多个函数链接在一起非常有用:

> add3 $ add3 $ add3 $ add3 $ 1 + 1

更好
> add3 (add3 (add3 (add3 (1 + 1))))

因为你不必关闭括号。

答案 1 :(得分:7)

好吧,正如已经说过的那样,$可以很容易地被理解,如果你只是忘记了currying并且看起来就像在C ++中那样

template<typename A, typename B>
B dollar(std::function<B(A)> f, A x) {
  return f(x);
}

但实际上,除了将函数应用于某个值之外,还有更多内容! $map的签名之间的明显相似性实际上是一个非常深刻的类别理论意义:两者都是仿函数的变形行为的例子!

在我们一直使用的 Hask 类别中,对象是类型。 (That is a bit confusionsome,但不要担心)。态射是函数。

最着名的(endo - )仿函数是那些具有the eponymous type class实例的仿函数。但实际上,在数学上,仿函数只是将对象映射到对象和态射到映射 1 的东西。 map(双关语,我想!)是一个例子:它接受一个对象(即类型)A并将其映射到类型[A]。并且,对于任何两种类型AB,它需要一个态射(即函数)A -> B,并将其映射到类型为[A] -> [B]的相应列表函数。< / p>

这只是仿函数类签名操作的一个特例:

fmap :: Functor f   =>   (a->b) -> (f a->f b)

数学并不要求这个fmap有一个名字。因此,还可以使用身份仿函数,它只是为自己分配任何类型。并且,每个态度都是自己的:

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

&#34;标识&#34;显然更普遍存在,你也可以将任何类型的值映射到自己。

id :: a -> a
id x = x

当然,可能的实施是

($) = id

1 介意,不是任何映射对象和态射是一个仿函数......它确实需要满足functor laws

答案 2 :(得分:6)

($)只是功能应用。它获得类型a->b的函数,类型为a的参数,应用函数并返回类型为b的值。

map是阅读函数类型签名有助于理解它的一个很好的例子。 map的第一个参数是一个带a并返回b的函数,它的第二个参数是[a]类型的列表。 因此mapa->b类型的函数应用于a值列表。结果类型确实是[b]类型 - b值的列表!

(a->b)->[a]->[b]可以解释为&#34;接受一个函数和一个列表并返回另一个列表&#34;,并且还作为&#34;接受类型a->b的函数并返回另一个[a]->[b]&#34;类型的函数。 当你以这种方式看待它时,map&#34;升级&#34; f(术语&#34; lift&#34;经常在这个上下文中使用)来处理列表:如果double是一个加倍整数的函数,那么map double是一个加倍的函数列表中的整数。