Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么在haskell中可以定义没有参数的函数_Haskell_Functional Programming_Partial Application - Fatal编程技术网

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

为什么在haskell中可以定义没有参数的函数,haskell,functional-programming,partial-application,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 addOne :: Int -> Int addOne = add 1 或无显式参数 addOne :: Int -> Int addOne y = add 1 y addOne :: Int -&

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

add :: Int -> (Int -> Int)
add x y = x + y
可以使用显式参数定义addOne

addOne :: Int -> Int
addOne y = add 1 y
addOne :: Int -> Int
addOne = add 1
或无显式参数

addOne :: Int -> Int
addOne y = add 1 y
addOne :: Int -> Int
addOne = add 1
我有四个问题:

  • 为什么我可以在没有显式参数的情况下定义新函数
  • 这两个定义有什么区别吗
  • 我什么时候知道什么时候可以定义没有参数的函数
  • 首选哪种定义以及何时
  • 因为
    addOne y=add1y
    意味着
    addOne=\y->add1y
    ,而
    \x->fx
    总是
    f
    。这被称为eta等价。所以
    addOne=add1

  • 没有

  • 总是。函数参数只是lambdas的语法糖:

    add :: Int -> Int -> Int
    add = \x y -> x + y
    
    是否可以完全删除变量绑定是另一回事

  • 如果可以,“eta reduce”(即,当函数绑定中最右边的绑定变量与绑定表达式中的函数应用程序相匹配时,将其删除)总是很好的,因为这样可以避免引入多余的名称


  • 在函数式编程中,使用Haskell需要学习的一个基本概念是函数只是一种值,定义只是命名。它不像过程语言那样在函数和变量之间有着明显的区别,函数定义与变量定义完全不同

    所以一个变量定义如下

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

    您的
    添加
    定义:

    add :: Int -> (Int -> Int)
    add x y = x + y
    
    也是一个变量定义。这是sugar Haskell提供的一点语法:

    add :: Int -> Int -> Int
    add = \ x -> \ y -> x + y
    
    基于更容易阅读的理论。但它仍然只是糖;您永远不会像在其他语言中一样需要它(请参见下面的[1])


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

    您应该查看CurrId函数和部分应用程序:考虑案例<代码> StrcI::INT--> String > String < /Cord>;code>strTake=take
    。所有这些都是为
    take
    创建一个别名,它只在
    String
    s上工作,而不是在任何类型的列表上工作。您不需要定义参数,只需将一个值设置为另一个值。然后,你可以考虑一些类似的东西:<代码> to5::[a] -> [a] < /代码>;code>take5=take5
    。还有一个教程:还要注意,因为
    ->
    是右关联的,
    Int->(Int->Int)
    Int->Int
    相同。与其他一些语言不同,Haskell中的这两种类型没有区别。正如其他人所指出的,无论您是否将函数实现为显式lambda,有时都会对优化或单态限制产生影响。我要补充的是,一些编辑器支持集成,这非常有助于告诉您何时可以减少,省去了您自己查找所有这些实例的麻烦。第二,
    hlint
    非常适合这样做。这很有趣!至于问题2,GHC优化器有一个区别,但这可能是我们不应该在这里混淆人们的东西。