Reputation: 205
In section Incorrectly matching against a variable from chapter 3 of real world haskell, there is an example as follows:
-- file: ch03/BogusPattern.hs
data Fruit = Apple | Orange
apple = "apple"
orange = "orange"
whichFruit :: String -> Fruit
whichFruit f = case f of
apple -> Apple
orange -> Orange
The explanation says in case f of
part, apple
and orange
are not treated as global variables as defined before the function declaration. They are local variables.I thought if there is no local variable owning the same name as a global variable, the global variable is not hidden.
Upvotes: 0
Views: 2298
Reputation: 24802
The main thing here is that variables in pattern matches always introduce new variables instead of referring to existing ones. Your problem has nothing to do with global vs local variables.
If you want to match the value of f
to the value of some variable like apple
in a pattern you need to use pattern guards and equality tests. E.g.
whichFruit f
| f == apple = Apple
| f == orange = Orange
Upvotes: 4
Reputation: 120711
Right. But there is a local variable apple
here owning the same name as the global variable apple
, namely apple
(duh).
The crucial thing about patterns is that they don't so much compare variables as look out for specific distinguishing features, while simultaneously re-packaging all other information into new variables. The "distinguishing features" are constructor matches (always uppercase1), which don't appear in case f of { apple -> ... }
, so simply all the information is passed on in the variable apple
.
data Vegetable = Tomato | Potato
data Edible = Fruit Fruit | Vegetable Vegetable
If you want a function to take an Edible
argument, it's often useful to deconstruct the type. This might look thus:
canJuice :: Edible -> Bool
canJuice (Fruit Apple) = False
canJuice (Fruit Orange) = True
canJuice (Vegetable Tomato) = True
canJuice (Vegetable Potato) = False
Now, for more complicated data it's awkward to write such lots of canJuice
clauses. An alternative would be to first match only on the outmost constructor, and delegate the further work elsewhere:
canJuice :: Edible -> Bool
canJuice (Fruit fruit) = fruitJuicy fruit
canJuice (Vegetable veg) = vegetableJuicy veg
vegetableJuicy :: Vegetable -> Bool
vegetableJuicy Tomato = True
vegetableJuicy Potato = False
For this to work, we needed Haskell's feature of treating any lowercase name appearing in a pattern as a new variable, which takes on the value in the "hole" of our pattern match.
1 There are also infix constructors, the best-known is list-cons (:)
(they all start with a colon, like all named constructors start uppercase).
Upvotes: 1
Reputation: 48664
You have hit upon irrefutable patterns
. As the book mentions, plain variable names and the wild card _
are examples of irrefutable patterns. Another example which will demonstrate irrefutable patterns
more clearly:
data Fruit = Apple | Orange deriving (Show)
patternMatch f = case f of
something -> Apple
Now the above program typechecks with an warning. In ghci:
ghci> patternMatch 2
Apple
ghci> patternMatch "hi"
Apple
So basically the variable something
is an irrefutable pattern which matches anything.
Now,coming back to your example:
whichFruit :: String -> Fruit
whichFruit f = case f of
apple -> Apple
orange -> Orange
Here the variable apple
and orange
are irrefutable patterns. They doesn't refer to the global function which you have already created. In fact you can remove the global definition of apple
and orange
and compile them in order to get an idea. Whatever input you give, you will always get Apple
as an answer for the above code (since it is an irrefutable pattern):
ghci > whichFruit "apple"
Apple
ghci > whichFruit "orange"
Apple
ghci > whichFruit "pineApple"
Apple
How to use a global variable within a function in Haskell ?
That's pretty easy actually. Just use them in your function definition.
data Fruit = Apple | Orange deriving (Show)
apple = "apple"
orange = "orange"
giveFruit :: Fruit -> String
giveFruit Apple = apple
giveFruit Orange = orange
In ghci:
ghci> giveFruit Apple
"apple"
ghci> giveFruit Orange
"orange"
Using the variable in the function definition is straight forward.
What should be done if I want the variable to refer to a global variable owning the same name?
One way would be to use the entire module name to refer to it. Example:
module Fruit where
data Fruit = Apple | Orange deriving (Show)
apple = "apple"
orange = "orange"
giveFruit2 :: Fruit -> String
giveFruit2 apple = Fruit.apple
Upvotes: 1