Task: write a function that uses folding to convert a String to an
Int.
Problem I'm having: given the String "314159265358979323846", the
function should report an error because the integer equivalent of this
string is outside the range of Int. If I run my code (below), it
overflows silently and outputs garbage. How can I check that the
calculation "place * 10 + digitToInt c" is within the bounds of Int
before outputting it and report an error otherwise?
I can make this function work by returning Integer instead of Int, but
I think that's missing the point of the exercise in the book.
Thanks,
Alex
Solution so far:
-- file: exercise04-2.1.hs
-- Write a function that converts a string of digits into an integer.
import Data.Char
import Data.List
asIntFold :: String -> Int
asIntFold "" = error "cannot convert string"
asIntFold ('-':str) = -(asIntFold(str))
asIntFold str = foldl' addPlace 0 str
where addPlace place c
| not (isDigit c) = error "cannot convert
string"
| otherwise = place * 10 + digitToInt c
Int is evil. Use Integer instead of Int.
> Problem I'm having: given the String "314159265358979323846", the
> function should report an error because the integer equivalent of this
> string is outside the range of Int. If I run my code (below), it
> overflows silently and outputs garbage. How can I check that the
> calculation "place * 10 + digitToInt c" is within the bounds of Int
> before outputting it and report an error otherwise?
Int is Bounded, so you can use maxBound to check how high Ints get --
that should be enough of a clue? On my computer,
Prelude> maxBound :: Int
9223372036854775807
Prelude>
Somewhat alarmingly,
Prelude> signum (abs minBound :: Int)
-1
Prelude>
(-:
Mark
>> Task: write a function that uses folding to convert a String to an Int.
>
>Int is evil. Use Integer instead of Int.
One thing I like about Haskell is that we have Integer. But most
languages I've used get by without it, preferring efficiency. Why is
Int evil?
--
"In no part of the constitution is more wisdom to be found,
than in the clause which confides the question of war or peace
to the legislature, and not to the executive department."
- James Madison
Because you can add two positive Ints and get a negative Int, for
example.
The efficiency hit of Integer doesn't have to be so large. The compiler
can use an Int-like representation most of the time (say, when advised
by a pragma), with an overflow check on arithmetic operations. Overflow
could either promote to a bignum representation or raise an exception,
either of which is preferable to silently giving the wrong answer.
>Because you can add two positive Ints and get a negative Int, for
>example.
I'm still a Haskell beginner. How does this work, and why?
Same way as in C and other dangerous languages:
Prelude> let a = maxBound :: Int
Prelude> a
9223372036854775807
Prelude> a+5
-9223372036854775804
> Int is Bounded, so you can use maxBound to check how high Ints get --
> that should be enough of a clue?
Well, I saw maxBound, but the problem is I can't see how to compare
the value returned by maxBound to the result of a possibly overflowing
calculation because once the calculation is performed and silently
overflows it becomes, by the nature of overflow, a value within the
bounds of Int. For example, adding the guard
| (place * 10 + digitToInt c) > maxBound = error "cannot convert
string"
never gets executed because whenever (place * 10 + digitToInt c)
overflows, it returns a value between minBound and maxBound.
Yes, I can make it work when I use Integer, of course, but again, I
don't think that's the goal of the exercise.
You might check the value
1 + maxBound :: Int
However, using using that idea is only correct if Int is implemented as
two's complement, and though that is the case today, not always in the
past. So if you want not relying on how Int is implemented, you need to
check overflow before it happens.
Why not do the intermediate steps in Integer, where the comparison to
the Int maxBound would work, and only convert the final result of a
non-overflowing calculation to Int?
Patricia
I figured it was sign overflow that somehow wasn't checked by the
compiler. But why? All of the compilers in languages I have used
do check.
At any rate, for most use we don't need to check, as Int is only
"evil", as you say with pretty large numbers.
> On Sep 4, 7:35 pm, "Mark T. B. Carroll" <m...@bcs.org> wrote:
>
>> Int is Bounded, so you can use maxBound to check how high Ints get --
>> that should be enough of a clue?
>
> Well, I saw maxBound, but the problem is I can't see how to compare
> the value returned by maxBound to the result of a possibly overflowing
> calculation because once the calculation is performed and silently
> overflows it becomes, by the nature of overflow, a value within the
> bounds of Int.
You don't add the next digit to the current sum, to compare, you instead
check something like if maxBound `div` 10 is larger than your current
digit place, I'd guess. Something like that.
Mark
> I figured it was sign overflow that somehow wasn't checked by the
> compiler. But why? All of the compilers in languages I have used
> do check.
Still, quite a few don't. Some don't even check array bounds. Sometimes
it's a compile-time option. For instance, having a quick go with Java
now -- a fairly high-level language -- I find it lets ints overflow
quite silently.
> At any rate, for most use we don't need to check, as Int is only
> "evil", as you say with pretty large numbers.
Indeed. Many languages guarantee ints are at least so-large, Haskell
included I think.
Mark
Off the top of my head I can't think of any compilers that check, except
for those that promote to bignum automatically.
> At any rate, for most use we don't need to check, as Int is only
> "evil", as you say with pretty large numbers.
Almost all numbers are pretty large in that sense. Int is only non-evil
if the compiler can statically verify that the values will always be
sufficiently small.
> The efficiency hit of Integer doesn't have to be so large. The compiler
> can use an Int-like representation most of the time (say, when advised
> by a pragma), with an overflow check on arithmetic operations. Overflow
> could either promote to a bignum representation or raise an exception,
> either of which is preferable to silently giving the wrong answer.
Integers (in GHC) already use a machine integer representation when the
values are small enough, and only promote to a GMP arbitrary precision
integer on overflow.
The efficiency hit for Integer is doing all this, and the resulting
diminishment of optimizations.
If exception-on-overflow is preferable, there's the 'checked' library on
hackage that provides Data.Int/Word.Checked.
The 'checked' package is not written for speed - it does the
assertions by performing all operations both in the requested type and
then in Integer to see if we've gone out of bounds of the base type.
Also, the checkes are not performed when compiling with optimizations.
It was originally intended to be a diagnostic - something you can swap
in to characterize your operations.
Antoine
> Howard Brazee <how...@brazee.net> writes:
>>> Prelude> a+5
>>> -9223372036854775804
>>
>> I figured it was sign overflow that somehow wasn't checked by the
>> compiler. But why? All of the compilers in languages I have used
>> do check.
>
> Off the top of my head I can't think of any compilers that check, except
> for those that promote to bignum automatically.
ML implementations generally check, e.g. in SML/NJ:
- valOf(Int.maxInt) + 1;;
uncaught exception Overflow [overflow]
raised at: <file stdIn>
Ada also requires overflow checking, and implementations adhere to
that.