Reputation: 2305
I'm beginner in Haskell (currently learning pattern matching) and I tried to write simple function for defining vector:
vector :: (Num a) => a -> a -> String
vector 0 0 = "This vector has 0 magnitude."
vector x y = "This vector has a magnitude of " ++ show(sqrt(x^2 + y^2)) ++ "."
But I get bunch of errors which I don't understand at all.
helloworld.hs:9:8: error:
• Could not deduce (Eq a) arising from the literal ‘0’
from the context: Num a
bound by the type signature for:
vector :: Num a => a -> a -> String
at helloworld.hs:8:1-37
Possible fix:
add (Eq a) to the context of
the type signature for:
vector :: Num a => a -> a -> String
• In the pattern: 0
In an equation for ‘vector’:
vector 0 0 = "This vector has 0 magnitude."
helloworld.hs:10:51: error:
• Could not deduce (Show a) arising from a use of ‘show’
from the context: Num a
bound by the type signature for:
vector :: Num a => a -> a -> String
at helloworld.hs:8:1-37
Possible fix:
add (Show a) to the context of
the type signature for:
vector :: Num a => a -> a -> String
• In the first argument of ‘(++)’, namely
‘show (sqrt (x ^ 2 + y ^ 2))’
In the second argument of ‘(++)’, namely
‘show (sqrt (x ^ 2 + y ^ 2)) ++ "."’
In the expression:
"This vector has a magnitude of "
++ show (sqrt (x ^ 2 + y ^ 2)) ++ "."
helloworld.hs:10:56: error:
• Could not deduce (Floating a) arising from a use of ‘sqrt’
from the context: Num a
bound by the type signature for:
vector :: Num a => a -> a -> String
at helloworld.hs:8:1-37
Possible fix:
add (Floating a) to the context of
the type signature for:
vector :: Num a => a -> a -> String
• In the first argument of ‘show’, namely ‘(sqrt (x ^ 2 + y ^ 2))’
In the first argument of ‘(++)’, namely
‘show (sqrt (x ^ 2 + y ^ 2))’
In the second argument of ‘(++)’, namely
‘show (sqrt (x ^ 2 + y ^ 2)) ++ "."’
Failed, modules loaded: none.
Prelude> :load helloworld
[1 of 1] Compiling Main ( helloworld.hs, interpreted )
helloworld.hs:10:51: error:
• Could not deduce (Show a) arising from a use of ‘show’
from the context: Integral a
bound by the type signature for:
vector :: Integral a => a -> a -> String
at helloworld.hs:8:1-42
Possible fix:
add (Show a) to the context of
the type signature for:
vector :: Integral a => a -> a -> String
• In the first argument of ‘(++)’, namely
‘show (sqrt (x ^ 2 + y ^ 2))’
In the second argument of ‘(++)’, namely
‘show (sqrt (x ^ 2 + y ^ 2)) ++ "."’
In the expression:
"This vector has a magnitude of "
++ show (sqrt (x ^ 2 + y ^ 2)) ++ "."
helloworld.hs:10:56: error:
• Could not deduce (Floating a) arising from a use of ‘sqrt’
from the context: Integral a
bound by the type signature for:
vector :: Integral a => a -> a -> String
at helloworld.hs:8:1-42
Possible fix:
add (Floating a) to the context of
the type signature for:
vector :: Integral a => a -> a -> String
• In the first argument of ‘show’, namely ‘(sqrt (x ^ 2 + y ^ 2))’
In the first argument of ‘(++)’, namely
‘show (sqrt (x ^ 2 + y ^ 2))’
In the second argument of ‘(++)’, namely
‘show (sqrt (x ^ 2 + y ^ 2)) ++ "."’
Failed, modules loaded: none.
Can somebody explain me how to write this function properly, at least what's wrong with vector 0 0
?
Upvotes: 1
Views: 185
Reputation: 54971
The error messages tell you everything you need to know.
Could not deduce (Eq a)
When you use a pattern-match on a numeric literal, it needs the constraints (Eq a, Num a)
because Haskell uses ==
internally to do matching on literals.
Could not deduce (Show a)
When you use show
, you need the constraint (Show a)
, because not all types are showable by default.
Could not deduce (Floating a)
When you use fractional operations such as sqrt
, you need the constraint (Floating a)
, because not all numeric types support these operations.
Putting it all together:
vector :: (Eq a, Num a, Show a, Floating a) => a -> a -> String
vector 0 0 = "This vector has 0 magnitude."
vector x y = "This vector has a magnitude of " ++ show(sqrt(x^2 + y^2)) ++ "."
You could also leave off the type signature, then ask ghci:
> let vector 0 0 = "This vector has 0 magnitude."; vector x y = "This vector has a magnitude of " ++ show(sqrt(x^2 + y^2)) ++ "."
> :t vector
vector :: (Eq a, Floating a, Show a) => a -> a -> [Char]
And here you can see that you don’t need the extra Num a
constraint, because Floating
is a subclass of Num
, by way of Fractional
. You can get information on these classes in ghci as well:
> :info Floating
class Fractional a => Floating a where
pi :: a
exp :: a -> a
log :: a -> a
sqrt :: a -> a
...
-- Defined in ‘GHC.Float’
instance Floating Float -- Defined in ‘GHC.Float’
instance Floating Double -- Defined in ‘GHC.Float’
When writing very generic code like this, you generally have to specify all the constraints you use. But you could also give this function a simpler non-generic type such as Double -> Double -> String
.
Upvotes: 3
Reputation: 6695
The first type error is because you're pattern matching on the literal 0
. You've only required Num a
where you needed (Num a, Eq a)
in order for this to be possible.
The second type error is because you've tried to use show on a computation involving your a
. So now, you need (Num a, Eq a, Show a)
.
The third, because you've used sqrt, which does not reside in Num
but in Floating
, so now it's (Num a, Eq a, Show a, Floating a)
.
Alternatively, you could have just removed the type signature entirely and prompted ghci for the type:
λ> :t vector
vector :: (Show a, Floating a, Eq a) => a -> a -> [Char]
Note that Floating
implies Num
.
Upvotes: 6