It will infer you mean Integer if you just evaluate it, read what it says about ":set +t". Crudely put, `:t foo` puts a question to the interpeter that is about the expression "foo" - "in what sense can this expression be taken?" -- it would be tiresome but maybe a little clearer if `:t` demanded quotes. If you just ask it what 5 or (4 + 1) or 2+2+1 is, it will say that it is 5 and assume that we were talking about an `Integer` -- the command `:t it` gives the type it is associating with the sign it is exhibiting to you as the result of calculation or evaluation, the second sign, not the one you entered.
In the type query `:t 5`, ghci doesn't have to decide or resolve anything, it gives all the possibilities, `5: Num a => a`. But if it is to evaluate the expression it needs you or it to make decisions. You can see this pretty clearly in the following:
Prelude> :t 5
5 :: (Num t) => t
Prelude> 5
5
Prelude> :t it
it :: Integer
Prelude> 5 :: Float
5.0
Prelude> :m + Data.Ratio
Prelude Data.Ratio> 5 :: Rational
5 % 1
Prelude Data.Ratio> :t it
it :: Rational
In the first case, it decided, in the other two, I decided what type I meant.
I'm not sure I grasp everything about this, but in your example, `p [1,2,3,4,5]` ghci couldn't make its natural assumption - i.e. the one you in fact think should be it's natural assumption -- since no Monoid (in your sense) instance had been declared for its preferred case, Integer, so it backed off and demanded clarification.
You had unconsciously over-ruled the defaults you wanted. As has been pointed out, if you had realized that Integer is the name for Haskell's integer type, and Int a dirty approximation like Float, and had used it, everything would have gone as you claim to have wanted. In fact you get everything you want if you just add these lines to your module:
instance Monoid Integer
where
addId = 0
add = (+)
keeping all of the other Int stuff intact. Then in ghci can use its defaults -- the defaults you want -- and you get:
Ok, modules loaded: Main.
*Main> p [1,2,3,4,5]
(5x^4 + 4x^3 + 3x^2 + 2x + 1)
*Main> :t it
it :: UnivariatePolynomial Integer
Though of course the unevaluated expression is given a more general type:
*Main> :t p [1,2,3,4,5]
p [1,2,3,4,5] :: (Num t, Monoid t) =>
UnivariatePolynomial t
-- and rightly, since this very module permits an Int interpretation of the expression. In a case that goes against its defaults, I have to tell it that that's how I want the complex functional expression to be understood, before I ask for evaluation:
*Main> p [1,2,3,4,5] :: UnivariatePolynomial Int
(5x^4 + 4x^3 + 3x^2 + 2x + 1)
*Main> :t it
it :: UnivariatePolynomial Int
It is the same if you add another Monoid instance for the non-default reading of "1", e.g.
instance Monoid Float
where
addId = 0
add = (+)
This can exist side by side with the others. Then you get:
*Main> p [1,2,3,4,5] :: UnivariatePolynomial Float
(5.0x^4 + 4.0x^3 + 3.0x^2 + 2.0x + 1.0)
*Main> :t it
it :: UnivariatePolynomial Float
Note that even with three Monoid instances in play in the module, we still get what you wanted:
*Main> p [1,2,3,4,5]
(5x^4 + 4x^3 + 3x^2 + 2x + 1)
*Main> :t it
it :: UnivariatePolynomial Integer
What are your thoughts on this behavior overall? I mean, your opinion. When do we precisely know that '5' means '5::Integer'? At which point does GHC or really Haskell in general, I assume, make this decision?
I think I don't really have a view about this, I'm accustomed to ghci's behavior from practice. It's clear there are other ways of resolving these problems, but don't they all have downsides? It does seem excellent that ghci's preferred type for "5" is Integer, rather than Int, as I think you would agree on reflection.
Of course we know what defaulting is. Why is it bad? I don't think I myself would even notice if it weren't there, since I write type signatures before I write the value expressions for them. I guess it is convenient if you are noodling around in ghci. With -XOverloadedStrings you get the same effect:
ghci -XOverloadedStrings
Prelude> :m +Data.Text
Prelude Data.Text> "cargo cult"
"cargo cult"
Prelude Data.Text> :t it
it :: String
Prelude Data.Text> "cargo cult" :: Text
"cargo cult"
Prelude Data.Text> :t it
it :: Text
It defaults to String. What's wrong with this exactly? A general coercion, understood as something different from a function (pack, unpack), would have to coerce between two types of wildly different structures. One is a list type [Char] that you can map over and into from any kind of list you like - and the user is forever employing this fact - the other is totally different.
It is different from other systems, but doesn't that just mean you have to learn something different, which is of course annoying until it becomes second nature. There doesn't seem to be any legitimate technical objection here, or am I wrong?
Of course we know what defaulting is. Why is it bad?
I wonder who is that we you refer to. Is applicative a Bourbaki-style pseudonym for a group of aspiring Haskell hackers?
I never said it is bad, it looks like a useful and convenient mechanism. My complaint is about its non-genericity. Indeed, it is limited to numeric literals only; even to reuse it for string literals, you need a compiler extension.
A general coercion, understood as something different from a function (pack, unpack), would have to coerce between two types of wildly different structures.
By general coercion, I mean implicit conversion not limited to numeric literals (or string literals, with an extension) only.
By "we" I meant reikonomusha and myself, as the context made plain. I don't see how calling something an ugly hack isn't a form of calling it bad, but never mind.
Numeric and string literals are all that were ever under discussion. `OverloadedStrings` is a language extension, not a compiler extension; it is a candidate for inclusion in later specifications, not in the new Haskell 2010. The Ghc supports it with a language pragma. That it, and the associated IsString class, didn't exist in Haskell 98, the previous specification, is obviously due to the fact that there was not widespread use of types like ByteString and Text for handling text; if there had been it would have been, surely; the idea is pretty straightforward.