为什么你可以在haskell中定义没有参数的函数

时间:2014-10-23 16:40:03

标签: haskell functional-programming partial-application

我有部分应用的函数add来创建一个新函数addOne。

add :: Int -> (Int -> Int)
add x y = x + y

可以使用显式参数

定义addOne
addOne :: Int -> Int
addOne y = add 1 y

或没有explict参数

addOne :: Int -> Int
addOne = add 1

我有四个问题:

  1. 为什么我可以在没有显式参数的情况下定义新函数?
  2. 这两个定义之间有什么区别吗?
  3. 我何时知道何时可以在没有参数的情况下定义函数?
  4. 首选哪个定义?何时?

2 个答案:

答案 0 :(得分:5)

  1. 因为addOne y = add 1 y表示addOne = \y -> add 1 y\x -> f x始终只是f。这称为eta等价。所以addOne = add 1

  2. 没有

  3. 始终。函数参数只是lambdas的语法糖:

    add :: Int -> Int -> Int
    add = \x y -> x + y
    

    是否可以完全删除变量绑定是另一回事。

  4. 总是很高兴" eta reduce" (也就是说,当它与匹配表达式中的函数应用程序匹配时,删除函数绑定中最右边的绑定变量),因为它可以避免引入多余的名称。

答案 1 :(得分:4)

你需要学习使用Haskell的函数式编程的基本概念之一是函数只是一种值,定义只是命名。它不像过程语言, functions 变量之间有明显的区别,而且函数定义与变量定义完全不同。

所以像

这样的变量定义
addOne :: Int -> Int
addOne = add 1

只是为表达式add 1添加名称,因此您可以将其称为addOne。它与变量声明相同。[1]从Haskell的角度来看,该变量的值是函数的事实几乎是偶然的。

您的add定义:

add :: Int -> (Int -> Int)
add x y = x + y

也是变量定义。这是Haskell提供的一些语法糖:

add :: Int -> Int -> Int
add = \ x -> \ y -> x + y

理论上它更容易阅读。但它仍然只是糖;你永远不需要它(除了下面的[1]),就像你在其他语言中一样。

[1]:dreaded monomorphism restriction也在这里发挥作用。这个想法只是:在函数定义中,RHS将由计算机多次执行(与调用函数一样多次)。您可能从其他语言中了解到这一点。在单态变量定义中,RHS最多只执行一次,这也与其他语言的工作方式类似。但是,多态变量通常最终起到函数定义的作用,RHS的执行次数与访问变量值的次数相同。所以Haskell不允许多态定义,除非你有多态类型签名(所以你说“我知道我在做什么,允许这个变量是多态的”)或你左边有参数(所以它“看起来”比如“RHS应该多次执行”。