Reputation: 25
I'm learning Haskell and writing a simple program. Now I'm getting a problem, which for me, is quite confusing. Here is the code:
data VariableName = X|Y deriving Show
getValue :: VariableName -> Int
getValue X = 5
getValue Y = 13
data Expression = Constant|Variable|Add|Multiply deriving Show
evaluate :: Expression -> Int
evaluate Constant x = x
evaluate Variable x = getValue x
evaluate Add x y = x+y
evaluate Multiply x y = x * y
I expect the output:
Constant 20 = 20
but I'm getting
*Main> evaluate Constant 20
<interactive>:79:1: error:
Variable not in scope: evaluate :: t0 -> Integer -> t
<interactive>:79:10: error: Data constructor not in scope: Constant
But when e.g.: I write
*Main> getValue X
5
Which is the right answer. I just started Haskell, which is way this is quite confusing for me. Some help would be much appreciated.
Upvotes: 0
Views: 4258
Reputation: 2778
Let's take a look at the errors:
Variable not in scope: evaluate :: t0 -> Integer -> t Data constructor not in scope: Constant
These mean that you haven't defined the evaluate
function and the Constant
constructor (even though you clearly have). But you say when you use getValue
and X
, those work?
This doesn't appear to be the (extremely common) multiline ghci
confusion, as suggested in a comment. First, the error you get from that tends to be a non-exhaustive patterns
, which is not what you're getting. Second, your ghci
prompt reads *Main>
instead of Prelude>
, which implies that you've :load
ed a file. Said file simply hasn't defined the code you expect it to have.
My guess is that is you wrote the first part of the code in the file, then :load
ed it properly, then modified the file and forgot to :reload
, so the changes you made were never loaded.
Another possibility is that you put a module Main (VariableName (..), getValue) where
at the beginning of your file, and forgot to add your new exports to it. But that seems less likely.
If none of the above works, just try closing ghci
, opening it again, and :load
ing the file anew.
Even once you fix that issue, there are a number of other errors you'll run into, mostly to do with parentheses. In Haskell, When you write something like this:
evaluate Constant 20
It means "call the evaluate
function, and pass it two arguments: Constant
and 20
". This implies evaluate :: Expression -> Int -> Int
, but you really want evaluate :: Expression -> Int
. So you need parentheses:
evaluate (Constant 20)
This means "call the Constant
constructor with one argument 20
, and pass that value as the single argument to evaluate
".
Not only must you make this change at the call site, you also need it in the definition. Currently, you have:
evaluate :: Expression -> Int
evaluate Constant x = x
evaluate Variable x = getValue x
evaluate Add x y = x+y
evaluate Multiply x y = x * y
Each of these patterns expects a different number of arguments: the first two expect two arguments, and the last two expect three arguments. The problem is that x
and y
are being seen as arguments to the function, not the constructors. To change this, you need parentheses:
evaluate :: Expression -> Int
evaluate (Constant x) = x
evaluate (Variable x) = getValue x
evaluate (Add x y) = x+y
evaluate (Multiply x y) = x * y
The final change you need to make is in the constructor definition: you need to tell the constructors that they take arguments in the first place. Currently your data definition looks like this (I've added formatting):
data Expression = Constant
| Variable
| Add
| Multiply
deriving Show
None of these constructors currently take arguments: they're values (like True
, X
, Nothing
, etc), rather than value constructors. This is not what you want. You need to give the types of the arguments for each constructor, like so:
data Expression = Constant Int
| Variable VariableName
| Add Int Int
| Multiply Int Int
deriving Show
Upvotes: 1