Nikola Stojaković
Nikola Stojaković

Reputation: 2305

Function for defining vector doesn't work in Haskell

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

Answers (2)

Jon Purdy
Jon Purdy

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

Sarah
Sarah

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

Related Questions