【问题标题】:Why can you define function without parameter in haskell为什么可以在haskell中定义没有参数的函数
【发布时间】:2014-10-23 16:40:03
【问题描述】:

我有函数 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

我有四个问题:

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

【问题讨论】:

  • 你应该看看 curried 函数partial applicationhaskell.org/haskellwiki/Currying
  • 考虑案例strTake :: Int -> String -> StringstrTake = take。所有这一切都是为take 创建一个别名,该别名仅适用于Strings 而不是任何类型的列表。你不需要定义参数,你只是设置一个值等于另一个值。然后你可以考虑类似take5 :: [a] -> [a]; take5 = take 5.
  • 还要注意,因为-> 是右结合,Int -> (Int -> Int)Int -> Int -> Int 相同。与其他一些语言不同,Haskell 中的这两种类型没有区别。正如其他人所指出的,无论您是否将函数实现为显式 lambda,有时确实会对优化或单态性限制产生影响。

标签: haskell functional-programming partial-application


【解决方案1】:
  1. 因为addOne y = add 1 y 表示addOne = \y -> add 1 y,而\x -> f x 始终只是f。这称为 eta 等价性。所以addOne = add 1

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

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

    能不能完全去掉变量绑定是另外一回事。

  3. 如果可以,最好使用“eta reduce”(即,当函数绑定与绑定表达式中的函数应用程序匹配时,删除函数绑定中最右边的绑定变量),因为它可以避免引入多余的名称。

【讨论】:

  • 我会补充一点,一些编辑器支持hlint 集成,这非常适合告诉您何时可以进行 eta reduce,从而节省您自己查找所有这些实例的工作量。
  • 其次,hlint 非常适合。减少 Eta 很有趣!
  • 至于问题 2,GHC 优化器是有区别的,但这可能是我们不应该在这里混淆的东西。
【解决方案2】:

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

所以像这样的变量定义

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应该被执行多次)。

【讨论】:

    猜你喜欢
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 2020-10-03
    相关资源
    最近更新 更多