所以我有一个返回函数的函数。返回的函数应该为除x 之外的所有输入返回0。对于x,它应该返回10。
g x = do
let
f x = 10
f _ = 0
f
但是函数总是返回10:
(g 3) 4
10
似乎参数x与用于创建函数f的x不同。那我怎么能实现呢?
答案 0 :(得分:3)
您的方法似乎是尝试使用pattern matching类似unification - Haskell不执行统一,模式匹配仅适用于数据构造函数(例如Just
) ,而不是价值观。
您在内部定义shadows中使用的名称x
外部定义中使用的名称x
- 因此您的内部函数等同于:
f x = 10
您应该使用不同的变量名,并使您的内部函数将其参数与外部函数的参数进行比较:
g x = let f y = if x == y then 10 else 0
in f
或使用currying,这可以说是更好的风格:
g x y = if x == y then 10 else 0
这在语义上等同于上面的版本,并且在语义上等同于返回lambda的函数。我们可以将g
部分应用于一个值来生成一个带有一个参数的函数,例如:
> (g 3) 4
0
> (g "hi") "hi"
10
答案 1 :(得分:1)
模式匹配“f X ”仅当 X 是文字或数据构造函数(如“True”)时才将参数与 X 进行比较。当 X 是一个变量时,它会绑定一个新变量 - 在这种情况下,另一个“x”会遮挡外部变量。你必须使用良好的旧比较。例如,有警卫:
f y | x == y = ...
f _ = ...
答案 2 :(得分:1)
Haskell不允许统一具有相同名称的变量。
例如,f x x = ...
是语法错误,而不是说“当第一个和第二个参数相等时匹配这种情况”。
在您的情况下,您有相同的概念问题,但没有语法错误,因为一旦您尝试使用x
中的参数匹配它,Haskell只会从g
隐藏f
。由于在没有构造函数的情况下匹配变量x
是无条件的,因此它总是成功并返回10.
你想要一个像这样的函数:
g x = \y -> if x == y then 10 else 0
明确使用(==)
运算符。