0

I am writing the haversine formula in haskell. In one version of my function, the definition and declarations are as follows:

haversine :: Double -> Double -> Double -> Double -> Double
haversine lat1 lon1 lat2 lon2 = let dlon = (toRad lon2) - (toRad lon1)
                                    dlat = (toRad lat2) - (toRad lat1)
                                    a = sin(dlat/2)^2 + cos(lat1)*cos(lat2)*sin(dlon/2)^2
                                    c = 2 * asin(sqrt(a))
                                in c*r

This function compiles fine. When I change the declaration to:

haversine :: (Double a) => a -> a -> a -> a -> a

I get the following error:

• Expecting one fewer argument to ‘Double’
  Expected kind ‘* -> *’, but ‘Double’ has kind ‘*’
• In the type signature:
    haversine :: (Double a) -> a -> a -> a -> a -> a

To my knowledge, by writing (Double a), I am subjecting the rest of the parameters labeled 'a' to the Double type class constraint. Why does the latter declaration result in this error?

2
  • You changed the first type declaration from Double -> to Double => when you changed the second from (Double a) -> to (Double a) =>. This can't possibly be correct so I have taken the liberty of editing it back to Double ->. Commented Jul 13, 2017 at 17:41
  • Double is "constant" type constructor. It takes no argument. You can check it with :k Double in ghci. Commented Jul 16, 2017 at 13:02

2 Answers 2

4

1) Double a isn't a valid constraint. You're looking for Floating a

2) Constraints are given on the left hand side of a =>, unlike function arguments which are on the left hand side of a ->.

So to compile, your code should be

haversine :: Floating a => a -> a -> a -> a -> a
haversine lat1 lon1 lat2 lon2 = let dlon = (toRad lon2) - (toRad lon1)
                                    dlat = (toRad lat2) - (toRad lat1)
                                    a = sin(dlat/2)^2 + cos(lat1)*cos(lat2)*sin(dlon/2)^2
                                    c = 2 * asin(sqrt(a))
                                in c*r

Assuming you have globally defined

r :: Floating a => a
toRad :: Floating a => a -> a
Sign up to request clarification or add additional context in comments.

3 Comments

Why isn't Double a valid constraint? Isn't Double an instance of Floating?
Constraints constrain a type to a class. Double isn't a class.
Like MathematicalOrchid says, Double is a type, not a constraint. In Haskell, just as types live in a different world than values, constraints live in a different world than types. To be technical, they have a different kind. A simple data type like Double has kind *. Types of kind * are the only types that have values. Maybe has kind * -> *. It maps a type of kind * (like Double) to a new type of kind * (like Maybe Double). Floating is a typeclass and has kind * -> Constraint. It maps a type of kind * to a constraint.
4

In Haskell, a type and a class are two different things.

There is a type named Double.

There is no class named Double.

Also, a class constraint must be followed by =>, not ->.

You can constrain a variable by a class such as Eq, Show, etc. If you want it to be a specific type... well, just write that type instead of a variable.

1 Comment

I guess Skalla could write haversine :: (a ~ Double) => a -> a -> a -> a -> a to constrain a to be Double, but that'd be highly non-idiomatic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.