I want to crate a tuple, that holds an arrow and a string that describes the arrow. If i do so with functions (instead of arrows), the following works like expected:
funTimes10 = (*10)
describe10 = "times 10"
tuple10 :: (Num b) => ((b -> b), String)
tuple10 = (,) funTimes10 describe10
I can access the function with fst, and with snd i get the description string of the function.
However, if i exchange the function with an arrow, like in the following:
aTuple10 :: (Arrow a, Num b) => (a b b, String)
aTuple10 = (,) (arr funTimes10) describe10
fststill works and returns my arrow, but- i don’t get any description string with
snd.
I only got this error-message:
Ambiguous type variable `a0' in the constraint:
(Arrow a0) arising from a use of `aTuple10'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `snd', namely `aTuple10'
In the expression: (snd aTuple10)
In an equation for `it': it = (snd aTuple10)
Why do i get this error, and what should i do, to avoid it?
Let’s look at the type of
snd:(I renamed the type variables for clarity)
What the type states is that for a tuple with types
fooandx, return something of typex. Something important to know here is that while the value system aka. runtime in Haskell is lazy, Haskell’s type system is strict, meaning that both the types offooandxmust be known beforesndcan be called.In the first case, when you just have a
Num b => (b -> b, String), callingsndwill leavebambiguous, because you don’t mention its concrete type anywhere, and it can’t be inferred from the return type becausefoo ~ bwhich is distinct fromx. In other words: because(b, b)can be a tuple of any number type, and the type checker can’t figure out which one, it is ambiguous. The trick here is that we’ll have Haskell’s defaulting rules kick in, which state that if a numeric type is ambiguous, it should default toInteger. If you had turned warnings on with-Wall, it would have said that this is happening. So, our type becomes(Integer -> Integer, String)andsndcan be called.In the second case, however, we still manage to infer
bvia the defaulting rules, but there is no defaultArrowfora, so we’re stuck! You must explicitly specify which arrow you want in order to continue! You can either do this by first using a value ofaTuple10somewhere else:… or you can just specify the type that you want:
PS if you want to change the default type of ambiguous numbers, the
defaultkeyword can help you out.