Ambiguous type variables with Haskell functional dependencies - haskell

I was playing around with the FunctionalDependencies-Extension of Haskell, along with MultiParamTypeClasses. I defined the following:
class Add a b c | a b -> c where
(~+) :: a -> b -> c
(~-) :: a -> b -> c
neg :: a -> a
zero :: a
which works fine (I've tried with instances for Int and Double with the ultimate goal of being able to add Int and Doubles without explicit conversion).
When I try to define default implementations for neg or (~-) like so:
class Add ...
...
neg n = zero ~- n
GHCi (7.0.4) tells me the following:
Ambiguous type variables `a0', `b0', `c0' in the constraint:
(Add a0 b0 c0) arising from a use of `zero'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `(~-)', namely `zero'
In the expression: zero ~- n
In an equation for `neg': neg n = zero ~- n
Ambiguous type variable `a0' in the constraint:
(Add a0 a a) arising from a use of `~-'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: zero ~- n
In an equation for `neg': neg n = zero ~- n
I think I do understand the problem here. GHC does not know which zero to use, since it could be any zero yielding anything which in turn is fed into a ~- which we only know of, that it has an a in it's right argument and yields an a.
So how can I specify that it should be the zero from the very same instance, i.e. how can I express something like:
neg n = (zero :: Add a b c) ~- n
I think the a, b and c here are not the a b c form the surrounding class, but any a b and c, so how can I express a type which is a reference to the local type variables?

Pull neg and zero out into a superclass that only uses the one type:
class Zero a where
neg :: a -> a
zero :: a
class Zero a => Add a b c | a b -> c where
(~+) :: a -> b -> c
(~-) :: a -> b -> c
The point is that your way, zero :: Int could be the zero from Add Int Int Int, or the zero from Add Int Double Double, and there is no way to disambiguate between the two, regardless of whether you're referring to it from inside a default implementation or an instance declaration or normal code.
(You may object that the zero from Add Int Int Int and the zero from Add Int Double Double will have the same value, but the compiler can't know that someone isn't going to define Add Int Char Bool in a different module and give zero a different value there.)
By splitting the typeclass into two, we remove the ambiguity.

You cannot express the zero function as part of the Add class. All type variables in the class declaration must be encountered in the type declaration for each function of the class; otherwise, Haskell won't be able to decide which type instance to use because it is given too few constraints.
In other words, zero is not a property of the class you are modelling. You are basically saying: "For any three types a, b, c, there must exist a zero value for the type a", which makes no sense; you could pick any b and c and it would solve the problem, hence b and c are completely unusable, so if you have an Add Int Int Int or an Add Int (Maybe String) Boat, Haskell does not know which instance to prefer. You need to separate the property of negation and "zeroness" into a separate class(es) of types:
class Invertible a where
invert :: a -> a
neg :: Invertible a => a -> a
neg = invert
class Zero a where
zero :: a
class Add a b c | a b -> c where
(~+) :: a -> b -> c
(~-) :: a -> b -> c
I don't see why you would then even need the Invertible and Zero constraints in Add; you can always add numbers without knowing their zero value, can you not? Why express neg as a requirement for ~+; there are some numbers that should be addable without them being negatable (Natural numbers for instance)? Just keep the class concerns separate.

Related

Difference between -> and => symbols. What do they mean?

In Haskell, when we talk type declaration.
I've seen both -> and =>.
As an example: I can make my own type declaration.
addMe :: Int -> Int -> Int
addMe x y = x + y
And it works just fine.
But if we take a look at :t sqrt we get:
sqrt :: Floating a => a -> a
At what point do we use => and when do we use ->?
When do we use "fat arrow" and when do we use "thin arrow"?
-> is for explicit functions. I.e. when f is something that can be written in an expression of the form f x, the signature must have one of these arrows in it†. Specifically, the type of x (the argument) must appear to the left of a -> arrow.
It's best to not think of => as a function arrow at all, at least at first‡. It's an implication arrow in the logical sense: if a is a type with the property Floating a, then it follows that the signature of sqrt is a -> a.
For your addMe example, which is a function with two arguments, the signature must always have the form x -> y -> z. Possibly there can also be a q => in front of that; that doesn't influence the function-ishness, but may have some saying in what particular types are allowed. Generally, such constraints are not needed if the types are already fixed and concrete. Like, you could in principle impose a constraint on Int:
addMe :: Num Int => Int -> Int -> Int
addMe x y = x + y
...but that doesn't really accomplish anything, because everybody knows that the particular type Int is an instance of the Num class. Where you need such constraints is when the type is not fixed but a type variable (i.e. lowercase), i.e. if the function is polymorphic. You can't just write
addMe' :: a -> a -> a
addMe' x y = x + y
because that signature would suggest the function works for any type a whatsoever, but it can't work for all types (how would you add, for example, two strings? ok perhaps not the best example, but how would you multiply two strings?)
Hence you need the constraint
addMe' :: Num a => a -> a -> a
addMe' x y = x + y
This means, you don't care what exact type a is, but you do require it to be a numerical type. Anybody can use the function with their own type MyNumType, but they need to ensure that Num MyNumType is fulfilled: then it follows that addMe' can have signature MyNumType -> MyNumType -> MyNumType.
The way to ensure this is to either use a standard type which you know to be numerical, for instance addMe' 5.9 3.7 :: Double would work, or give an instance declaration for your custom type and the Num class. Only do the latter if you're sure it's a good idea; usually the standard num types are all you'll need.
†Note that the arrow may not be visible in the signature: it's possible to have a type synonym for a function type, for example when type IntEndofunc = Int -> Int, then f :: IntEndofunc; f x = x+x is ok. But you can think of the typedef as essentially just a syntactic wrapper; it's still the same type and does have the arrow in it.
‡It so happens that logical implication and function application can be seen as two aspects of the same mathematical concept. Furthermore, GHC actually implements class constraints as function arguments, so-called dictionaries. But all this happens behind the scenes, so if anything they're implicit functions. In standard Haskell, you will never see the LHS of a => type as the type of some actual argument the function is applied to.
The "thin arrow" is used for function types (t1 -> t2 being the type of a function that takes a value of type t1 and produces a value of type t2).
The "fat arrow" is used for type constraints. It separates the list of type constraints on a polymorphic function from the rest of the type. So given Floating a => a -> a, we have the function type a -> a, the type of a function that can take arguments of any type a and produces a result of that same type, with the added constraint Floating a, meaning that the function can in fact only be used with types that implement the Floating type class.
the -> is the constructor of functions and the => is used to constraints, a sort of "interface" in Haskell called typeclass.
A little example:
sum :: Int -> Int -> Int
sum x y = x + y
that function only allows Int types, but if you want a huge int or a small int, you probably want Integer, and how to tell it to use both?
sum2 :: Integral a => a -> a -> a
sum2 x y = x + y
now if you try to do:
sum2 3 1.5
it will give you an error
also, you may want to know if two data are equals, you want:
equals :: Eq a => a -> a -> Bool
equals x y = x == y
now if you do:
3 == 4
that's ok
but if you create:
data T = A | B
equals A B
it will give to you:
error:
• No instance for (Eq T) arising from a use of ‘equals’
• In the expression: equals A B
In an equation for ‘it’: it = equals A B
if you want for that to work, you must just do:
data T = A | B deriving Eq
equals A B
False

Can I make a polymorphic `mult` function, that takes any numeric type?

I'm learning Haskell. This is the very first program that I've ever wrote and I just thought of making a simple function that returns the product of the given arguments.
mult :: a -> a -> a
mult x y = x * y
When I write it this way, I get an "inferred type" error.
ERROR "uno.hs":5 - Inferred type is not general enough
*** Expression : mult
*** Expected type : a -> a -> a
*** Inferred type : Integer -> Integer -> Integer
It wants me to write it this way:
mult :: Int -> Int -> Int
mult x y = x * y
...which works perfectly fine, but then I wonder... can't this function work on Floats as well?
It can.
mult :: Float -> Float -> Float
mult x y = x * y
--then
mult 4 5 == 20.0
Finally, I wonder:
Can I make a polymorphic mult function, that takes any numeric type?
Why does the parser infers Integrer from a function that also works with other types?
I found no answers so far, yet this seems like a simple question. I'll be grateful for help me.
Short answer: mult :: Num a => a -> a -> a and it picked Integer because it felt like it was a good choice.
Long answer:
mult can't be a -> a -> a because that would mean it works on every type a, including String, Char, Bool, etc. The Num a => part is called a constraint, and it restricts what a can be by requiring that it is an instance of the Num type class. It's like saying "this function works on any type, as long as that type has the properties (has an instance) of this specific type class". The properties for the Num type class are defined in the standard library, linked below.
It's worth noting that the type of (*) itself is Num a => a -> a -> a, and that your function mult could also have been defined as mult = (*).
The reason it told you to use Integer -> Integer -> Integer is because the default for Num is Integer. You should never rely on this being the case, and should instead write out the full, type class constrained type signature.
When you specified the type signature Float -> Float -> Float, the compiler specializes the function to only work on Floats, as you would expect. This resolves the "over-promising" problem arising from a -> a -> a by choosing a specific type for a that the compiler knows has a Num instance.
Read more about type classes here, and the specific definition of Num is documented here and the code is linked on the side of the page. (Not enough rep to post the link directly)

How can an arbitrary Num contain any other numeric type?

I'm just starting with Haskell, and I thought I'd start by making a random image generator. I looked around a bit and found JuicyPixels, which offers a neat function called generateImage. The example that they give doesn't seem to work out of the box.
Their example:
imageCreator :: String -> IO ()
imageCreator path = writePng path $ generateImage pixelRenderer 250 300
where pixelRenderer x y = PixelRGB8 x y 128
when I try this, I get that generateImage expects an Int -> Int -> PixelRGB8 whereas pixelRenderer is of type Pixel8 -> Pixel8 -> PixelRGB8. PixelRGB8 is of type Pixel8 -> Pixel8 -> Pixel8 -> PixelRGB8, so it makes sense that pixelRenderer is doing some type inference to determine that x and y are of type Pixel8. If I define a type signature that asserts that they are of type Int (so the function gets accepted by generateImage, PixelRGB8 complains that it needs Pixel8s, not Ints.
Pixel8 is just a type alias for Word8. After some hair pulling, I discovered that the way to convert an Int to a Word8 is by using fromIntegral.
The type signature for fromIntegral is (Integral a, Num b) => a -> b. It seems to me that the function doesn't actually know what you want to convert it to, so it converts to the very generic Num class. So theoretically, the output of this is a variable of any type that fits the type class Num (correct me if I'm mistaken here--as I understand it, classes are kind of like "interfaces" where types are more like classes/primitives in OOP). If I assign a variable
let n = fromIntegral 5
:t n -- n :: Num b => b
So I'm wondering... what is 'b'? I can use this variable as anything, and it will implicitly cast to any numeric type, as it seems. Not only will it implicitly cast to a Word8, it will implicitly cast to a Pixel8, meaning fromPixel effectively gets turned from (as I understood it) (Integral a, Num b) => a -> b to (Integral a) => a -> Pixel8 depending on context.
Can someone please clarify exactly what's happening here? Why can I use a generic Num as any type that fits Num, both mechanically and "ethically"? I don't understand how the implicit conversion is implemented (if I were to create my own class, I feel like I would need to add explicit conversion functions). I also don't really know why this works; here I can use a pretty unsafe type and convert it implicitly to anything else. (for example, fromIntegral 50000 gets translated to 80 if I implicitly convert it to a Word8)
A common implementation of type classes such as Num is dictionary-passing. Roughly, when the compiler sees something like
f :: Num a => a -> a
f x = x + 2
it transforms it into something like
f :: (Integer -> a, a -> a -> a) -> a -> a
-- ^-- the "dictionary"
f (dictFromInteger, dictPlus) x = dictPlus x (dictFromInteger 2)
The latter basically says: "pass me an implementation for these methods of class Num for your type a, and I will use them to produce a function a -> a for you".
Values such as your n :: Num b => b are no different. They are compiled into things such as
n :: (Integer -> b) -> b
n dictFromInteger = dictFromInteger 5 -- roughly
As you can see, this turns innocent-looking integer literals into functions, which can (and does) impact performance. However, in many circumstances the compiler can realize that the full polymorphic version is not actually needed, and remove all the dictionaries.
For instance, if you write f 3 but f expects Int, the "polymorphic" 3 can be converted at compile time. So type inference can aid the optimization phase (and user-written type annotation can greatly help here). Further, some other optimizations can be triggered manually, e.g. using the GHC SPECIALIZE pragma. Finally, the dreaded monomorphism restriction tries hard to force non-functions to remain non-functions after translation, at the cost of some loss of polymorphism. However, the MR is now being regarded as harmful, since it can cause puzzling type errors in some contexts.

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)

Type class definition with functions depending on an additional type

Still new to Haskell, I have hit a wall with the following:
I am trying to define some type classes to generalize a bunch of functions that use gaussian elimination to solve linear systems of equations.
Given a linear system
M x = k
the type a of the elements m(i,j) \elem M can be different from the type b of x and k. To be able to solve the system, a should be an instance of Num and b should have multiplication/addition operators with b, like in the following:
class MixedRing b where
(.+.) :: b -> b -> b
(.*.) :: (Num a) => b -> a -> b
(./.) :: (Num a) => b -> a -> b
Now, even in the most trivial implementation of these operators, I'll get Could not deduce a ~ Int. a is a rigid type variable errors (Let's forget about ./. which requires Fractional)
data Wrap = W { get :: Int }
instance MixedRing Wrap where
(.+.) w1 w2 = W $ (get w1) + (get w2)
(.*.) w s = W $ ((get w) * s)
I have read several tutorials on type classes but I can find no pointer to what actually goes wrong.
Let us have a look at the type of the implementation that you would have to provide for (.*.) to make Wrap an instance of MixedRing. Substituting Wrap for b in the type of the method yields
(.*.) :: Num a => Wrap -> a -> Wrap
As Wrap is isomorphic to Int and to not have to think about wrapping and unwrapping with Wrap and get, let us reduce our goal to finding an implementation of
(.*.) :: Num a => Int -> a -> Int
(You see that this doesn't make the challenge any easier or harder, don't you?)
Now, observe that such an implementation will need to be able to operate on all types a that happen to be in the type class Num. (This is what a type variable in such a type denotes: universal quantification.) Note: this is not the same (actually, it's the opposite) of saying that your implementation can itself choose what a to operate on); yet that is what you seem to suggest in your question: that your implementation should be allowed to pick Int as a choice for a.
Now, as you want to implement this particular (.*.) in terms of the (*) for values of type Int, we need something of the form
n .*. s = n * f s
with
f :: Num a => a -> Int
I cannot think of a function that converts from an arbitary Num-type a to Int in a meaningful way. I'd therefore say that there is no meaningful way to make Int (and, hence, Wrap) an instance of MixedRing; that is, not such that the instance behaves as you would probably expect it to do.
How about something like:
class (Num a) => MixedRing a b where
(.+.) :: b -> b -> b
(.*.) :: b -> a -> b
(./.) :: b -> a -> b
You'll need the MultiParamTypeClasses extension.
By the way, it seems to me that the mathematical structure you're trying to model is really module, not a ring. With the type variables given above, one says that b is an a-module.
Your implementation is not polymorphic enough.
The rule is, if you write a in the class definition, you can't use a concrete type in the instance. Because the instance must conform to the class and the class promised to accept any a that is Num.
To put it differently: Exactly the class variable is it that must be instantiated with a concrete type in an instance definition.
Have you tried:
data Wrap a = W { get :: a }
Note that once Wrap a is an instance, you can still use it with functions that accept only Wrap Int.

Resources