我有部分应用的函数add来创建一个新函数addOne。
add :: Int -> (Int -> Int)
add x y = x + y
可以使用显式参数
定义addOneaddOne :: Int -> Int
addOne y = add 1 y
或没有explict参数
addOne :: Int -> Int
addOne = add 1
我有四个问题:
答案 0 :(得分:5)
因为addOne y = add 1 y
表示addOne = \y -> add 1 y
,\x -> f x
始终只是f
。这称为eta等价。所以addOne = add 1
。
没有
始终。函数参数只是lambdas的语法糖:
add :: Int -> Int -> Int
add = \x y -> x + y
是否可以完全删除变量绑定是另一回事。
总是很高兴" 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应该多次执行”。