Haskell: meaning of the error in GHCI - haskell

I'm not able to figure out what this error msg means. I want to define the function distance for the data type below... I do NOT want to use any GHC extensions.. even if the code is ugly, want to understand the error better, before I move on to using the extensions. Can someone please let me know what this error means and how I can get rid of this.
class Vector v where
distance :: v -> v -> Double
-- doesn't make sense, but WTH...
newtype OneD1 a = OD1 a
deriving (Show)
instance Vector (Maybe m) where
distance _ _ = 5.6
instance Vector (OneD1 m) where
distance (OD1 x1) (OD1 x2) = x2-x1
Prelude> :reload
[1 of 1] Compiling Main ( VectorTypeClass.hs, interpreted )
VectorTypeClass.hs:33:33:
Couldn't match expected type `Double' with actual type `m'
`m' is a rigid type variable bound by
the instance declaration
at C:\Users\byamm\Documents\Programming\Haskell\Lab\Expts\VectorTypeClass\VectorTypeClass.hs:32:10
Relevant bindings include
x2 :: m
(bound at C:\Users\byamm\Documents\Programming\Haskell\Lab\Expts\VectorTypeClass\VectorTypeClass.hs:33:27)
x1 :: m
(bound at C:\Users\byamm\Documents\Programming\Haskell\Lab\Expts\VectorTypeClass\VectorTypeClass.hs:33:18)
distance :: OneD1 m -> OneD1 m -> Double
(bound at C:\Users\byamm\Documents\Programming\Haskell\Lab\Expts\VectorTypeClass\VectorTypeClass.hs:33:4)
In the first argument of `(-)', namely `x2'
In the expression: x2 - x1
Failed, modules loaded: none.
Prelude>

instance Vector (OneD1 m) where
This promises that (OdeD1 m) is a vector, for any m. Including OneD1 String, etc.
distance (OD1 x1) (OD1 x2) = x2-x1
Here we try to apply - on two values of type m, which could be absolutely anything. There are two issues here:
m might not be a numeric type -- GHC is not reporting this error, at the moment.
the result of the difference is again of type m, but distance should produce a Double. This is the error GHC is reporting.
You need to restrict m to some numeric type, so that you can use -, and that type must admit a conversion to Double, otherwise you can't satisfy the distance signature.
One trivial way is:
instance Vector (OneD1 Double) where
distance (OD1 x1) (OD1 x2) = x2-x1
Another could be:
instance Real m => Vector (OneD1 m) where
distance (OD1 x1) (OD1 x2) = realToFrac (x2-x1)

Related

Type mismatch in signature and locally introduced term

Consider the following code:
-- | Parse a 64bit word in little-endian format.
word64le :: Get ByteString e Word64
word64le = do
s <- elems 8
pure $ foldl' (.|.) 0 [shiftL (fromIntegral b) (i * 8) | (i, b) <- zip [0 .. 7] (atomize s)]
Per the comment, this reads out a Word64 from a ByteString by first pulling an 8-byte ByteString (the elems call), then unpacking it (the atomize call) and doing the obvious shift left dance. So far so good. Now this code can very obviously be generalized to other machine integral types, we just need to get hold of the number of bits of such a type and that is supplied by the FiniteBits class. So doing the generalization:
-- | Parse an integral word in little-endian format.
integralLe :: (FiniteBits w, Integral w, Bounded w) => Get ByteString e w
integralLe = do
s <- elems (fromIntegral n)
pure $ foldl' (.|.) 0 [shiftL (fromIntegral b) (i * 8) | (i, b) <- zip [0 .. n - 1] (atomize s)]
where
n = finiteBitSize (minBound :: w) `quot` 8
This does not work, with GHC complaining that "Could not deduce (Bounded w1) arising from a use of ‘minBound’ from the context: (FiniteBits w, Integral w, Bounded w)". So it seems that my type annotation minBound :: w is not enough to convince GHC that I mean the same w as in the function signature; is my diagnosis correct? And if yes, how do I tell GHC that the two w types are the same?
note(s):
on GHC 9.2 with a nightly stackage.
sorry about the poor question title, but cannot think of anything better.
edit(s):
per the comment added {-# LANGUAGE ScopedTypeVariables #-} at the top of the file but having the same error, namely "Could not deduce (Bounded w2) arising from a use of ‘minBound’ from the context: (FiniteBits w, Integral w, Bounded w) bound by the type signature for:"
Aha. If I add an explicit forall e w . in the function signature to the left of the constraint it works, even without the ScopedTypedVariables extensions (maybe because I am using language GHC2021). No on, to understand why the heck this works...
Haskell has some... let's charitably call it "weird"... rules for how type variables are scoped by default.
-- | Parse an integral word in little-endian format.
integralLe :: (FiniteBits w, Integral w, Bounded w) => Get ByteString e w
integralLe = do
s <- elems (fromIntegral n)
pure $ foldl' (.|.) 0 [shiftL (fromIntegral b) (i * 8) | (i, b) <- zip [0 .. n - 1] (atomize s)]
where
n = finiteBitSize (minBound :: w) `quot` 8
You're right that Haskell will throw an implicit forall w at the start of the integralLe type signature, but it's not actually a ScopedTypeVariables forall. By default, the scope of that variable is just that one line. It is not considered a type variable inside of any type ascriptions or signatures in where clauses, let clauses, or anything else inside the function. That's where ScopedTypeVariables comes in. With ScopedTypeVariables, an explicit forall makes the type variable available lexically to anything inside of the function body, including where blocks. (And, as you've correctly noted, ScopedTypeVariables is included in GHC2021). Hence,
integralLe :: forall w. (FiniteBits w, Integral w, Bounded w) => Get ByteString e w
will work.

Easy function gives compile error on conversion from Int to Double

Why does this easy function which computes the distance between 2 integer points in the plane not compile?
distance :: (Int, Int) -> (Int, Int) -> Double
distance (x, y) (u, v) = sqrt ((x - u) ^ 2 + (y - v) ^ 2)
I get the error Couldn't match expected type ‘Double’ with actual type ‘Int’.
It is frustrating such an easy mathematical function consumes so much of my time. Any explanation why this goes wrong and the most elegant way to fix this is appreciated.
This is my solution to overcome the problem
distance :: (Int, Int) -> (Int, Int) -> Double
distance (x, y) (u, v) =
let xd = fromIntegral x :: Double
yd = fromIntegral y :: Double
ud = fromIntegral u :: Double
vd = fromIntegral v :: Double
in sqrt ((xd - ud) ^ 2 + (yd - vd) ^ 2)
but there must be a more elegant way.
Most languages only do type inference (if any) “in direction of data flow”. E.g., you start with a value 2 in Java or Python, that'll be an int. You calculate something like 2 + 4, and the + operator infers from the integer arguments that the result is also int. In dynamic languages this is the only way that's possible at all (because the types are only an “associated property” of values). In static languages like C++, the inference-step is only done once at compile time, but it's still done largely “as if the types were associated properties of values”.
Not so in Haskell. Like other Hindley-Milner languages, it has a type system that works completely independent of any runtime data flow directions. It can still do forward-inference ((2::Int) + (4::Int) is unambiguously of type Int), but it's only a special case – types can just as well be inferred in the “reverse direction”, i.e. if you write (x + y) :: Int the compiler is able to infer that both x and y must have type Int as well.
This reverse-polymorphism enables many nice tricks – example:
Prelude Debug.SimpleReflect> 2 + 4 :: Expr
2 + 4
Prelude Debug.SimpleReflect> 7^3 :: Expr
7 * 7 * 7
...but it only works if the language never does implicit conversions, not even in “safe†, obvious cases” like Int -> Integer.
Usually, the type checker automatically infers the most sensible type. For your original implementation, the checker would infer the type
distance :: Floating a => (a, a) -> (a, a) -> a
and that – or perhaps the specialised version
distance :: (Double,Double) -> (Double,Double) -> Double
is a much more sensible type than your (Int, Int) -> ... attempt, because the Euclidean distance makes actually no sense on a discrete grid (you'd want something like a Taxcab distance there).
What you'd actually want is distance from the vector-space package. This is more general, works not only on 2-tuples but any suitable space.
†Int -> Double is actually not a safe conversion – try float(1000000000000000001) in Python! So even without Hindley-Milner, this is not really a very smart thing to do implicitly.
SOLVED: now I have this
distance :: (Int, Int) -> (Int, Int) -> Double
distance (x, y) (u, v) = sqrt (fromIntegral ((x - u) ^ 2 + (y - v) ^ 2))

Typeclass instances with constrained return type

I'm implementing a notion of inner product that's general over the container and numerical types. The definition states that the return type of this operation is a (non-negative) real number.
One option (shown below) is to write all instances by hand, for each numerical type (Float, Double, Complex Float, Complex Double, Complex CFloat, Complex CDouble, etc.). The primitive types aren't many, but I dislike the repetition.
Another option, or so I thought, is to have a parametric instance with a constraint such as RealFloat (which represents Float and Double).
{-# language MultiParamTypeClasses, TypeFamilies, FlexibleInstances #-}
module Test where
import Data.Complex
class Hilbert c e where
type HT e :: *
dot :: c e -> c e -> HT e
instance Hilbert [] Double where
type HT Double = Double
dot x y = sum $ zipWith (*) x y
instance Hilbert [] (Complex Double) where
type HT (Complex Double) = Double
a `dot` b = realPart $ sum $ zipWith (*) (conjugate <$> a) b
Question
Why does the instance below not work ("Couldn't match type e with Double.. expected type HT e, actual type e")?
instance RealFloat e => Hilbert [] e where
type HT e = Double
dot x y = sum $ zipWith (*) x y
Well, that particular instance doesn't work because the sum only yields an e, but you want the result to be Double. As e is constrained to RealFrac, this is easy to fix though, as any Real (questionable though is is mathematically) can be converted to a Fractional:
dot x y = realToFrac . sum $ zipWith (*) x y
However, that generic instance prevents you from also defining complex instances: with instance RealFloat e => Hilbert [] e where you cover all types, even if they aren't really real numbers. You could still instantiate Complex as an overlapping instance, but I'd rather stay away from those if I could help it.
It's also questionable if such vectorspace classes should be defined on * -> * at all. Yes, linear also does it this way, but IMO parametricity doesn't work in our favour in this application. Have you checked out the vector-space package? Mind, it isn't exactly complete for doing serious linear algebra; that's a gap I hope to fill with my linearmap-category package.

Multi-parameter typeclass instance declarations

I am trying to understand multiparameter typeclasses but I just don't get the instance declarations. I am starting out trying to make an InnerProductSpace typeclass for a Vector type so that I can perform a dot product on two vectors. To start out I just wanted to see if I could multiply the first element of each vector. Here is my code
class InnerProductSpace a b c where
dot :: a -> b -> c
data Vector = Vector [Double]
deriving (Show)
instance InnerProductSpace Vector Vector Double where
dot (Vector a) (Vector b) = (head a * head b)
and the error after trying to use the dot function is
No instance for (InnerProductSpace Vector Vector c0)
arising from a use of `dot'
The type variable `c0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there is a potential instance available:
instance InnerProductSpace Vector Vector Double
-- Defined at Vector.hs:8:10
Possible fix:
add an instance declaration for
(InnerProductSpace Vector Vector c0)
In the expression: dot a b
In an equation for `it': it = dot a b
What did I do wrong? Thanks!
The problem is that the compiler doesn't know how to choose the right instance given what it knows. If you try something like
vectorA `dot` vectorA
the compiler goes searching for the right dot knowing that its type must be dot :: Vector -> Vector -> c0. Unfortunately, that's just not enough information by itself—c0 could be anything and the compiler never assumes that just because it only has a single instance it must be the correct one (this is related to the open world assumption---there might be another instance out there the compiler hasn't seen yet, so it prefers to just throw an error). You could get away with it by explicitly telling the compiler what the result ought to be
vectorA `dot` vectorB :: Double
but this is tedious and likely to fail a lot with numeric types since so often those types are generic as well. For instance, which instance of Num is used here?
(vectorA `dot` vectorB) + 3
We know it's Double, but the compiler can't prove that.
One solution is to use Type Families as #AndrewC suggests in the comment. I actually highly recommend that. The other solution you'll see in the wild is Functional Dependencies. These are written like this
class InnerProductSpace a b c | a b -> c where
dot :: a -> b -> c
and translate to entail a promise to the compiler: "knowing a and b is enough information to uniquely identify c". The compiler keeps you honest as well as it'll prevent you from writing instances that conflict on that promise.
instance InnerProductSpace Vector Vector Double where
dot (Vector a) (Vector b) = (head a * head b)
instance InnerProductSpace Vector Vector Float where
dot (Vector a) (Vector b) = (head a * head b)
---
/Users/tel/tmp/foo.hs:10:10:
Functional dependencies conflict between instance declarations:
instance InnerProductSpace Vector Vector Double
-- Defined at /Users/tel/tmp/foo.hs:10:10
instance InnerProductSpace Vector Vector Float
-- Defined at /Users/tel/tmp/foo.hs:13:10
But the promise gives the compiler exactly enough information to resolve the Double in the previous example.
Main*> (Vector [1,2,3]) `dot` (Vector [2,3,4]) + 3.0
5
or use TypeFamilies
class (D a b ~ c) => InnerProductSpace a b c where
type D a b
dot :: a -> b -> c
or
class InnerProductSpace a b where
type D a b :: *
dot :: a -> b -> D a b
instance InnerProductSpace Vector Vector where
type D Vector Vector = Double
dot (Vector a) (Vector b) = (head a * head b)

Unintuitive type signature in Haskell

I made this (what I thought to be) fairly straightforward code to calculate the third side of a triangle:
toRadians :: Int -> Double
toRadians d = let deg = mod d 360
in deg/180 * pi
lawOfCosines :: Int -> Int -> Int -> Double
lawOfCosines a b gamma = sqrt $ a*a + b*b - 2*a*b*(cos (toRadians gamma))
However, when I tried to load it into GHCi, I got the following errors:
[1 of 1] Compiling Main ( law_of_cosines.hs, interpreted )
law_of_cosines.hs:3:18:
Couldn't match expected type `Double' with actual type `Int'
In the first argument of `(/)', namely `deg'
In the first argument of `(*)', namely `deg / 180'
In the expression: deg / 180 * pi
law_of_cosines.hs:6:26:
No instance for (Floating Int)
arising from a use of `sqrt'
Possible fix: add an instance declaration for (Floating Int)
In the expression: sqrt
In the expression:
sqrt $ a * a + b * b - 2 * a * b * (cos (toRadians gamma))
In an equation for `lawOfCosines':
lawOfCosines a b gamma
= sqrt $ a * a + b * b - 2 * a * b * (cos (toRadians gamma))
law_of_cosines.hs:6:57:
Couldn't match expected type `Int' with actual type `Double'
In the return type of a call of `toRadians'
In the first argument of `cos', namely `(toRadians gamma)'
In the second argument of `(*)', namely `(cos (toRadians gamma))'
It turns out the fix was to remove my type signatures, upon which it worked fine.
toRadians d = let deg = mod d 360
in deg/180 * pi
lawOfCosines a b gamma = sqrt $ a*a + b*b - 2*a*b*(cos (toRadians gamma))
And when I query the type of toRadians and lawOfCosines:
*Main> :t toRadians
toRadians :: (Floating a, Integral a) => a -> a
*Main> :t lawOfCosines
lawOfCosines :: (Floating a, Integral a) => a -> a -> a -> a
*Main>
Can someone explain to me what's going on here? Why the "intuitive" type signatures I had written were in fact incorrect?
The problem is in toRadians: mod has the type Integral a => a -> a -> a, therefore, deg has the type Integral i => i (so either Int or Integer).
You then try and use / on deg, but / doesn't take integral numbers (divide integrals with div):
(/) :: Fractional a => a -> a -> a
The solution is to simply use fromIntegral :: (Integral a, Num b) => a -> b:
toRadians :: Int -> Double
toRadians d = let deg = mod d 360
in (fromIntegral deg)/180 * pi
Seeing Floating a and Integral a in a type signature together always sets off my internal alarm bells, as these classes are supposed to be mutually exclusive - at least, there are no standard numeric types that are instances of both classes. GHCi tells me (along with a lot of other stuff):
> :info Integral
...
instance Integral Integer -- Defined in `GHC.Real'
instance Integral Int -- Defined in `GHC.Real'
> :info Floating
...
instance Floating Float -- Defined in `GHC.Float'
instance Floating Double -- Defined in `GHC.Float'
To see why these classes are mutually exclusive, let's have a look at some of the methods in both classes (this is going to be a bit handwavy). fromInteger in Integral converts an Integral number to an Integer, without loss of precision. In a way, Integral captures the essence of being (a subset of) the mathematical integers.
On the other hand, Floating contains methods such as pi and exp, which have a pronounced 'real number' flavour.
If there were a type that was both Floating and Integral, you could write toInteger pi and have a integer that was equal to 3.14159... - and that's not possible :-)
That said, you should change all your type signatures to use Double instead of Int; after all, not all triangles have integer sides, or angles that are an integral number of degrees!
If you absolutely don't want that for whatever reason, you also need to convert the sides (the a and b arguments) in lawOfCosines to Double. That's possible via
lawOfCosines aInt bInt gamma = sqrt $ a*a + b*b - 2*a*b*(cos (toRadians gamma)) where
a = fromInteger aInt
b = fromInteger bInt
The type signature for toRadians says it takes an Int but returns a Double. In some programming languages, the conversion from one to the other (but not back) happens automatically. Haskell is not such a language; you must manually request conversion, using fromIntegral.
The errors you are seeing are all coming from various operations which don't work on Int, or from trying to add Int to Double, or similar. (E.g., / doesn't work for Int, pi doesn't work for Int, sqrt doesn't work for Int...)

Resources