“功能箭头与右边相关”的用处是什么?

时间:2015-05-25 14:15:33

标签: haskell

阅读http://www.seas.upenn.edu/~cis194/spring13/lectures/04-higher-order.html表明

  

特别要注意,功能箭头与右侧相关联   是,W - > X - > Y - > Z等于W - > (X - >(Y - > Z))。我们可以   始终在最右边的顶级箭头周围添加或删除括号   在一个类型。

函数箭头与右侧相关联,但是当函数应用程序与左侧相关联时,此信息的用处是什么?我觉得我不理解对我来说这是一个无意义的点,功能箭头与右边相关联。由于函数应用程序始终与左侧相关联,那么这是我应该关注的唯一关联性吗?

5 个答案:

答案 0 :(得分:13)

  

功能箭头与右侧相关但[...]此信息的用处是什么?

如果您看到类型签名,例如f : String -> Int -> Bool,您需要知道函数箭头的关联性,以了解f的类型是什么:

  1. 如果箭头与左侧相关联,则类型表示(String -> Int) -> Bool,即f将函数作为参数并返回布尔值。
  2. 如果箭头与右侧相关联,则类型表示String -> (Int -> Bool),即f将字符串作为参数并返回一个函数。
  3. 这是一个很大的区别,如果你想使用f,你需要知道它是哪一个。由于函数箭头与右侧相关联,因此您知道它必须是第二个选项:f接受一个字符串并返回一个函数。

      

    与右侧[...]功能应用程序相关联的功能箭头与左侧

    相关联

    这两个选择很好地协同工作。例如,我们可以将上面的f称为f "answer" 42,这实际上意味着(f "answer") 42。所以我们将字符串"answer"传递给f,返回一个函数。然后我们将数字42传递给该函数,该函数返回一个布尔值。实际上,我们几乎使用f作为具有两个参数的函数。

    这是在Haskell中使用两个(或多个)参数编写函数的标准方法,因此它是一个非常常见的用例。由于函数应用程序和函数箭头的关联性,我们可以编写这个没有括号的常见用例。

答案 1 :(得分:5)

在定义双参数curried函数时,我们通常会写这样的东西:

f :: a -> b -> c
f x y = ...

如果箭头没有与右侧相关联,则上述类型必须拼写为a -> (b -> c)。因此->关联性的有用性在于它在声明函数类型时不会编写太多括号。

答案 2 :(得分:1)

如果运算符#是'右关联',则表示:

a # b # c # d  =  a # (b # (c # d))

...对于任意数量的论点。它的行为类似于foldr

这意味着:

a -> b -> c -> d  =  a -> (b -> (c -> d))

注意:a -> (b -> (c -> d)) =/= ((a -> b) -> c) -> d!这非常重要。

这告诉我们的是,foldr

λ> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b

使用类型为(a -> b -> b)的函数,然后返回...一个带b的函数,然后返回...一个带[a]的函数,然后返回... b。这意味着我们可以应用这样的函数

f a b c

,因为

f a b c  =  ((f a) b) c
每次给出参数时,

f将返回两个函数。

基本上,这不是非常有用的,但它是我们想要解释和调用函数类型的重要信息。

然而,在像(++)这样的函数中,关联性很重要。如果(++)是关联的,那么它会很慢,所以它是正确的关联。

答案 3 :(得分:0)

早期的函数式语言Lisp遭受过度嵌套的括号(这使得代码(甚至文本(如果你不介意考虑更广泛的上下文))难以阅读。随着时间的推移,功能语言设计者选择使功能代码易于阅读并且为专业人士写信,即使是以不太统一的规则来混淆新手的费用。

在功能代码中, 函数类型声明,如(String - > Int) - > Bool比String这样的函数更为罕见 - > (Int - > Bool),因为返回函数的函数是函数式的商标。因此,将箭头关联到右侧有助于减少括号数(在超出时,您可能需要将函数映射到基本类型)。对于功能应用程序,反之亦然。

答案 4 :(得分:0)

主要目的是方便,因为部分功能应用程序从左到右。

每次将函数部分应用到一组值时,其余类型必须有效。

您可以将箭头类型视为类型队列,其中队列本身就是类型。在部分函数应用程序中,您从队列中将与类型数量一样多的类型从队列中出队,从而产生队列中的剩余内容。结果队列仍然是有效类型。

这就是为什么类型关联到右侧。如果类型与左侧关联,它将表现得像一个堆栈,并且您将无法以同样的方式部分应用它,而不会留下“漏洞”或未定义的域。例如,假设您具有以下功能:

foo :: a -> b -> c -> d

如果Haskell类型是左关联的,则将单个参数传递给foo将产生以下无效类型:

((? -> b) -> c) -> d

然后您将被迫通过添加括号来绕开它,这可能会影响可读性。