1

So I have a function that returns a function. The returned function is supposed to return 0 for all inputs except x. For x it should return 10.

g x = do
        let 
            f x = 10
            f _ = 0  
        f

But instead the function always returns 10:

(g 3) 4 
10

It seems that the parameter x is no the same x that gets used to create the function f. So how can I achieve that?

Luca9984
  • 141
  • 6

3 Answers3

3

Your approach seems to be trying to use pattern matching like it's unification - Haskell doesn't perform unification, and pattern matching only works for things like data constructors (eg. Just), not for values.


The name x you're using in the inner definition shadows the name x used in the outer definition - so your inner function is equivalent to:

f x = 10

You should use a different variable name, and make your inner function compare its argument to the outer function's argument:

g x = let f y = if x == y then 10 else 0
      in f

Or using currying, which is arguably better style:

g x y = if x == y then 10 else 0

This is semantically equivalent to the above version, and is also semantically equivalent to a function returning a lambda. We can partially apply g to a value to produce a function taking one parameter, eg:

> (g 3) 4
0
> (g "hi") "hi"
10
hnefatl
  • 5,860
  • 2
  • 27
  • 49
1

Pattern-matching "f X" compares argument with X only if X is a literal or data constructor (like "True"). When X is a variable it binds a new variable - in this case another "x" which shadows the outer one. You have to use good old comparison. For example, with guards:

f y | x == y = ...
f _ = ...
max630
  • 8,762
  • 3
  • 30
  • 55
1

Haskell does not allow unification of variables that share the same name.

For example, f x x = ... is a syntax error rather than to say "match this case when the first and the second arguments are equal".

In your case, you have the same conceptual problem but no syntax error because Haskell simply shadows x from g once you try to match it using an argument in f. As matching a variable x without a constructor is unconditional it always succeeds and returns 10.

You want a function like this:

g x = \y -> if x == y then 10 else 0

which uses the (==) operator explicitly.

madgen
  • 747
  • 3
  • 15