Haskell:初学者函数语法混乱

时间:2011-10-26 20:16:30

标签: haskell

我目前正在尝试学习Haskell,但我正在努力理解语法。例如,取map函数:

map :: (s -> t) -> [s] -> [t]
map f [] = []
map f (x:xs) = f x : map f xs

我理解该函数的作用,map有一个函数f :: s -> t作为参数。但我读map :: (s -> t) -> [s] -> [t]为“map是一个函数,它将函数映射从s映射到s再映射到s然后映射到t”,这显然是错误的。有人能帮我解决这个问题吗?

4 个答案:

答案 0 :(得分:17)

类型(s -> t) -> [s] -> [t]可以通过两种方式阅读。一种方法是将其视为两个参数的函数,第一个是类型s -> t的函数,第二个是类型[s]的列表。返回值的类型为[t]

另一种方法是理解函数箭头是右关联的,因此类型等同于(s -> t) -> ([s] -> [t])。根据这种解释,map是一个函数,它将一个函数从元素接收到元素s -> t,并将其转换为列表到列表[s] -> [t]的函数。

同样,在使用该函数时,您可以将map foo xs视为将函数map应用于两个参数fooxs。或者,由于函数应用程序 left -associative,您可以将其视为(map foo) xs,将map应用于单个参数foo以获取新函数然后将其应用于xs

由于Haskell函数是curried,所以这只是看待完全相同的两种方式。

答案 1 :(得分:2)

定义几个类型的别名可能会有所帮助,使它更明确地表示所有这些箭头和括号正在做什么:

type F1 a b = a -> b  -- type synonym for single-argument functions
type List a = [a]  -- type synonym for lists

现在您可以将map的类型签名写为:

map :: F1 s t -> List s -> List t

如果你对Java或C ++或其他什么更熟悉,那么在语法上看起来更像:

List<T> map(F1<S, T> fun, List<S> list); // applies fun to each element in list

所以你可以这样想:map接受一个函数和一个列表,然后返回另一个列表。但是,由于函数在Haskell中 curry ,因此您不必一次传递所有参数。您可以将部分应用 map放到第一个参数中。所以它的类型签名更像是:

F1<List<S>, List<T>> map(F1<S, T> fun); // returns a function that applies fun to each element in a list

...当你只用map个参数调用fun时,会给你一些类似的东西:

List<T> mapFun(List<S> list); // applies fun to each element in list

现在回到Haskell:您可以将map :: (s -> t) -> [s] -> [t]读作:

  • map s t 的函数和 s 的列表,并返回< EM>吨“
  • map s t 获取一个函数,并将其转换为 列表中的函数一个列表t

前者很好;后者更有帮助。

答案 2 :(得分:1)

“map”是一个函数,它将(函数从s到t)映射到(给出一个(t)列表的s列表中)? 这是将类型签名直接翻译成英文(虽然不是很优雅的英文)。

答案 3 :(得分:1)

从最后阅读签名:-> [t]表示返回t 列表。其余的是“常规”参数。

因此,map采用s生成t的函数和s列表。

现在很简单:使用函数s->t,将其应用于[s]的每个元素,其结果为[t]