instance Enum Double considered not entirely great?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
82 messages Options
12345
Reply | Threaded
Open this post in threaded view
|

instance Enum Double considered not entirely great?

Evan Laforge
So I've been excising occurrences of the [n..m] syntax from my code.
The reason is that I had been using [0..5] as a shorthand for [0, 1,
2, 3, 4, 5], mostly in tests.  This works for integral types and it
appears to work for floating point types.

Then I tried switching to a fixed point format, and discovered my
mistake.  Enum is supposed to enumerate every value between the two
points, and the result is memory exhaustion.  I had already been
switching from enumFrom because they accumulate floating point errors,
in favor of a couple of more appropriate functions:

-- | Enumerate an inclusive range.  Uses multiplication instead of successive
-- addition to avoid loss of precision.
--
-- Also it doesn't require an Enum instance.
range :: (Num a, Ord a) => a -> a -> a -> [a]
range start end step = go 0
    where
    go i
        | val > end = []
        | otherwise = val : go (i+1)
        where val = start + (i*step)

-- | Like 'range', but includes the end.
range_end :: (Num a, Ord a) => a -> a -> a -> [a]
range_end start end step = go 0
    where
    go i
        | val >= end = [end]
        | otherwise = val : go (i+1)
        where val = start + (i*step)

-- | Infinite range.
range_ :: (Num a) => a -> a -> [a]
range_ start step = go 0
    where go i = start + (i*step) : go (i+1)


So I think the Enum instances for Float and Double are sort of a trap.
 They misled me into thinking the .. syntax is the range function
defaulting to a step of 1, led to precision errors I had to debug then
fix (and I've noticed lead to the odd stack overflow question), then
led to more disaster when I switched to an Enum instance that lived up
to Enum's real purpose.  The problem is that the [..] syntax is
convenient and tempting, especially for tests, wanting a numeric range
(rather than enumeration) is very common, and as far as I know the
'range' function isn't in the standard library.

So it seems like one of these things that seem convenient in the short
term but come around and bite you later.  Using the right functions
from the start avoids all that.  Is there any support for the idea of
removing Enum instances for floating point numbers?

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Chris Smith-31
On Mon, 2011-09-19 at 22:09 -0700, Evan Laforge wrote:
> Then I tried switching to a fixed point format, and discovered my
> mistake.  Enum is supposed to enumerate every value between the two
> points, and the result is memory exhaustion.

I'm not sure where you read that "Enum is supposed to enumerate every
value between the two points".  It's not in the API documentation, and I
don't see it in the Haskell Report.

The better way to look at this is that the notion of `succ` and `pred`
is dependent on the type, much like `mappend` has no particular meaning
until a Monoid instance is given for the type.  It's fairly well
established, though undocumented, that Num types ought to have succ =
(+1) and pred = (subtract 1), so if your fixed point type doesn't do
that, I'd suggest it is the problematic part of this.

It would be a shame if we lost an occasionally useful and easy to read
language feature because of concerns with the disadvantages of some
hypothetical bad implementation.

> Is there any support for the idea of removing Enum instances for
> floating point numbers?

I certainly hope not.  Instead, perhaps the issue should be brought up
with the fixed-point number library you're using, and they could fix
their Enum instance to be more helpful.

--
Chris


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Jake McArthur
On Tue, Sep 20, 2011 at 10:59 AM, Chris Smith <[hidden email]> wrote:
> I certainly hope not.  Instead, perhaps the issue should be brought up
> with the fixed-point number library you're using, and they could fix
> their Enum instance to be more helpful.

I'm the author of the library in question. I intentionally chose the
semantics for Enum as it is, although I'm not sure I'm prepared to say
that Enum "should" have this behavior in general. Regardless,
enumerating all values makes more sense to me, and we still have
enumFromThen and enumFromThenTo, so no power is lost anyway. Float and
Double are the only types I know of that don't enumerate all values by
default in enumFrom and enumFromTo.

- Jake

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Jake McArthur
In reply to this post by Chris Smith-31
On Tue, Sep 20, 2011 at 10:59 AM, Chris Smith <[hidden email]> wrote:
> The better way to look at this is that the notion of `succ` and `pred`
> is dependent on the type, much like `mappend` has no particular meaning
> until a Monoid instance is given for the type.  It's fairly well
> established, though undocumented, that Num types ought to have succ =
> (+1) and pred = (subtract 1), so if your fixed point type doesn't do
> that, I'd suggest it is the problematic part of this.

I forgot to address this in my last email. I disagree that it is well
established for succ = (+1) and pred = subtract 1 for Num instances.
In fact, for types that are also instances of Bounded where the Num
instances have overflow this is required to be *not* true. Not
realizing this is a often a source of performance problems or even
bugs in Haskell programs.

- Jake

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Ketil Malde-5
In reply to this post by Chris Smith-31
Chris Smith <[hidden email]> writes:

> It would be a shame if we lost an occasionally useful and easy to read

You forgot "confusing"?  Expecting Enum to enumerate all inhabitants of
a type seems very reasonable to me, and seems to hold for all
non-floating point types.  A numeric range [a..a+n] might be expected
to have a+n+1 elements, but that doesn't hold either for Float and
Double.  I think Enum for floating point values is broken - but it is
reality, so we need to deal with it.

> Instead, perhaps the issue should be brought up with the fixed-point
> number library you're using, and they could fix their Enum instance to
> be more helpful.

Or just avoid Enum, and define "range" or something similar instead.

-k
--
If I haven't seen further, it is by standing in the footprints of giants

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Daniel Fischer
On Tuesday 20 September 2011, 17:39:49, Ketil Malde wrote:
> Chris Smith <[hidden email]> writes:
> > It would be a shame if we lost an occasionally useful and easy to read
>
> You forgot "confusing"?  Expecting Enum to enumerate all inhabitants of
> a type seems very reasonable to me, and seems to hold for all
> non-floating point types.

And Rational (more generally, Ratio a). (Why does everybody forget that?)
Enumerating all inhabitants of a type (within some range) is only possible
if there are well-defined successors and predecessors (modulo bounds).
For Double and Float, there are (excepting NaNs), so it could be done, but
arguably that would be *far less* useful than the current instances.
For Rational, no such luck.

> A numeric range [a..a+n] might be expected
> to have a+n+1 elements, but that doesn't hold either for Float and
> Double.  I think Enum for floating point values is broken

Yes, it is. Like Eq and Ord.

> - but it is reality, so we need to deal with it.

Like Eq and Ord, it's just too damn convenient to have it.
So much nicer to write [0, 0.25 .. 1000] instead of
numericEnumFromThenTo 0 0.25 1000
and (x /= y) instead of
doublesDifferentOrNaN x y

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Chris Smith-31
In reply to this post by Ketil Malde-5
On Tue, 2011-09-20 at 17:39 +0200, Ketil Malde wrote:
> You forgot "confusing"?

I didn't forget it; whether it's confusing or not depends on the
perspective you're coming from.  The kids in my beginning programming
class are using Enum (via the list syntactic sugar) on Float and don't
get confused... so perhaps we ought to ask what the cause of the
confusion is.

> Expecting Enum to enumerate all inhabitants of
> a type seems very reasonable to me, and seems to hold for all
> non-floating point types.

Floating point (and fixed point, for that matter) types approximate real
numbers, which of course have no possible enumeration of all values.
Even if you want to say they approximate rational numbers, it remains
the case that the rationals have no linearly ordered enumeration of all
their values, which would be needed to be compatible with the
approximation.  It seems to me particularly pointless to define an Enum
instance that focuses on, above all else, the inaccuracy of that
approximation.

Incidentally, you can add Rational to the list of types that define Enum
that way and don't enumerate all possible values.  And the Haskell
Report gives a generic implementation of Enum in terms of Num, which
behaves that way.  Perhaps I was understating the case in saying the
behavior was established but undocumented; rather, it's explicitly
documented in the Haskell Report, just not as a requirement for
programmer-defined instances of the Num class (because that's not the
job of the Report).

> Or just avoid Enum, and define "range" or something similar instead.

If Haskell defined list syntax in terms of something that's not called
Enum, that would be fine.  Renaming is never all that big a deal.  But
the list sugar is a big deal, and I don't think there's any point at all
in leaving the list sugar associated with something as minor as building
a representation of the inaccuracy of your approximations.

--
Chris


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Ross Paterson-2
In reply to this post by Daniel Fischer
Daniel Fischer writes:
>> A numeric range [a..a+n] might be expected
>> to have a+n+1 elements, but that doesn't hold either for Float and
>> Double.  I think Enum for floating point values is broken
>
>Yes, it is. Like Eq and Ord.

.. only more so.  And the brokenness has infected Rational: try

[1,3..20]::[Rational]
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Casey McCann-2
On Tue, Sep 20, 2011 at 12:47 PM, Paterson, Ross <[hidden email]> wrote:

> Daniel Fischer writes:
>>> A numeric range [a..a+n] might be expected
>>> to have a+n+1 elements, but that doesn't hold either for Float and
>>> Double.  I think Enum for floating point values is broken
>>
>>Yes, it is. Like Eq and Ord.
>
> .. only more so.  And the brokenness has infected Rational: try
>
> [1,3..20]::[Rational]

I actually think the brokenness of Ord for floating point values is
worse in many ways, as demonstrated by the ability to insert a value
into a Data.Set.Set and have other values "disappear" from the set as
a result. Getting an unexpected element in a list doesn't really seem
as bad as silently corrupting entire data structures.

For numeric ranges of fractional values, I expect that what one
typically wants is either "the two end points, and N intermediate
values evenly spaced" or "the starting value, and successive
increments up to some cut-off", with the default increment being 1 or
-1 as appropriate. The current Enum instance splits the difference and
gets you some of both, except that you might get the wrong values or
something past the cut-off. Similarly, the current Ord instance splits
the difference between a coherent total order (what Ord instances
should be) and the semantically correct partial order (what floats
should have, as defined in the IEEE standard).

- C.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Chris Smith-31
On Tue, 2011-09-20 at 15:28 -0400, Casey McCann wrote:
> I actually think the brokenness of Ord for floating point values is
> worse in many ways, as demonstrated by the ability to insert a value
> into a Data.Set.Set and have other values "disappear" from the set as
> a result.

Definitely Ord is worse.  I'd very much like to see the Ord instance for
Float and Double abandon the IEEE semantics and just put "NaN" somewhere
in there -- doesn't matter where -- and provide new functions for the
IEEE semantics.

As for Enum, if someone were to want a type class to represent an
enumeration of all the values of a type, then such a thing is reasonable
to want.  Maybe you can even reasonably wish it were called Enum.  But
it would be the *wrong* thing to use as a desugaring for list range
notation.  List ranges are very unlikely to be useful or even meaningful
for most such enumerations (what is [ Red, Green .. LightPurple]?); and
conversely, as we've seen in this thread, list ranges *are* useful in
situations where they are not a suitable way of enumerating all values
of a type.

--
Chris


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Jake McArthur
On Tue, Sep 20, 2011 at 3:48 PM, Chris Smith <[hidden email]> wrote:
> But it would be the *wrong* thing to use as a desugaring for list range
> notation.  List ranges are very unlikely to be useful or even meaningful
> for most such enumerations (what is [ Red, Green .. LightPurple]?); and
> conversely, as we've seen in this thread, list ranges *are* useful in
> situations where they are not a suitable way of enumerating all values
> of a type.

This makes me wonder if maybe the reason this discussion is happening
at all is that we don't have a well-defined meaning for what Enum
*is*. At this point, it seems like the only answer is that it's
whatever the instance says it is, which I find unsatisfying. What
exactly does Enum enumerate? To me, the list syntax sugar looks like
I'm specifying bounds, so it makes sense to include all values within
those bounds (and honestly, having instances for Float, Double, and
Rational sounds like a mistake, given this), but clearly that is not
what it means to everybody. What does it mean to you? What makes the
current behavior more useful than the proposed behavior? You say we've
seen that this behavior is useful in this thread, but I'm not sure
what it is we have seen.

- Jake

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirelygreat?

Donn Cave-4
In reply to this post by Chris Smith-31
Quoth Chris Smith <[hidden email]>,
...
> As for Enum, if someone were to want a type class to represent an
> enumeration of all the values of a type, then such a thing is reasonable
> to want.  Maybe you can even reasonably wish it were called Enum.  But
> it would be the *wrong* thing to use as a desugaring for list range
> notation.  List ranges are very unlikely to be useful or even meaningful
> for most such enumerations (what is [ Red, Green .. LightPurple]?); and
> conversely, as we've seen in this thread, list ranges *are* useful in
> situations where they are not a suitable way of enumerating all values
> of a type.

It isn't a life or death requirement, but I have dealt with enum values
that are ordered and that could usefully be represented in a range.
Even your example -- given a set of hues, it's sensible to order them
following the spectrum, so [Cyan .. YellowGreen] might represent the
hues in the set that are at all in the green range.

I'm frankly using Enum as an equivalent to C "enum", symbolic integers,
where the range is more or less implicit as by default the integer values
are [0..].  While I (vaguely) understand that Haskell's Enum is different,
the C idiom should at least testify that there's some practical value
in the notion of a range of Enum, or something like it.  Though not
with floating point values, of course.

        Donn

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Alexander Solla
In reply to this post by Jake McArthur


On Tue, Sep 20, 2011 at 1:22 PM, Jake McArthur <[hidden email]> wrote:
On Tue, Sep 20, 2011 at 3:48 PM, Chris Smith <[hidden email]> wrote:
> But it would be the *wrong* thing to use as a desugaring for list range
> notation.  List ranges are very unlikely to be useful or even meaningful
> for most such enumerations (what is [ Red, Green .. LightPurple]?); and
> conversely, as we've seen in this thread, list ranges *are* useful in
> situations where they are not a suitable way of enumerating all values
> of a type.

This makes me wonder if maybe the reason this discussion is happening
at all is that we don't have a well-defined meaning for what Enum
*is*.

Enum is the class that represents enumerable types.  In other words, the class of things that can be injected into the natural numbers.  These types inherit an order from the natural numbers, ordering by images under this injection.

Now, we might not like that order, and it might not agree with an Ord instance, but it exists.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Evan Laforge
In reply to this post by Jake McArthur
> This makes me wonder if maybe the reason this discussion is happening
> at all is that we don't have a well-defined meaning for what Enum
> *is*. At this point, it seems like the only answer is that it's

I agree, that's why I suggested a separate 'range' function.  I think
the "all values in this range" definition is reasonable (and
incidentally, Data.Fixed.Binary's Enum coincides with Data.Fixed, so I
think its the floats that are the odd ones out).  Enum is explicitly
not a numeric notion because it's meant to work for any enumeration
style ADT, so it seems clear to me it's about enumeration rather than
a numeric range.  There's clearly a lot of overlap between the two
interpretations, but we have Double taking Enum as a numeric range,
Data.Fixed taking it as an enumeration, integral types overlap so you
can't tell, and 'data C = Red | Green | Blue deriving Enum' is clearly
taking it as enumeration.

Some people have suggested that it's simply an ambiguous class which
has multiple interpretations, like Monoid, and thus you just need to
know which one you're dealing with.  Fair enough, but is that a good
thing?  I think it makes it harder to move between numeric types.  I
don't mind the Monoid thing because I haven't had to move between two
Monoid types and expect them to work similarly, but float -> fixed is
kind of like String -> Text in that its a likely axis of change.  I
would also be pretty surprised if Text came up with a different
interpretation of Monoid than String :)


On Tue, Sep 20, 2011 at 9:16 AM, Daniel Fischer
<[hidden email]> wrote:
>> - but it is reality, so we need to deal with it.
>
> Like Eq and Ord, it's just too damn convenient to have it.
> So much nicer to write [0, 0.25 .. 1000] instead of
> numericEnumFromThenTo 0 0.25 1000
> and (x /= y) instead of
> doublesDifferentOrNaN x y

Interestingly, "too damn convenient" was one of my motivations
*against* the instance.  It's not even that much more convenient, if
you write it 'range' then 'range 0 1000 0.25' is not much longer than
[0, 0.25 .. 1000], but, I'd argue the latter is a trap, and has a good
chance of causing a subtle bug in your app eventually if it gets big
enough.  The problem is that the list syntax is built-in and looks
nice and so is very tempting.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Casey McCann-2
In reply to this post by Chris Smith-31
On Tue, Sep 20, 2011 at 3:48 PM, Chris Smith <[hidden email]> wrote:

> On Tue, 2011-09-20 at 15:28 -0400, Casey McCann wrote:
>> I actually think the brokenness of Ord for floating point values is
>> worse in many ways, as demonstrated by the ability to insert a value
>> into a Data.Set.Set and have other values "disappear" from the set as
>> a result.
>
> Definitely Ord is worse.  I'd very much like to see the Ord instance for
> Float and Double abandon the IEEE semantics and just put "NaN" somewhere
> in there -- doesn't matter where -- and provide new functions for the
> IEEE semantics.

It should be first, to make floating point values consistent with
applying Maybe to a numeric type.

Personally, I contend that the most correct solution is to distinguish
between meaningful ordering relations and ones used for algorithmic
convenience. As another example, the type (Integer, Integer), regarded
as Cartesian coordinates, has no meaningful ordering at all but does
have an obvious arbitrary total order (i.e., the current Ord
instance). For purposes like implementing Data.Set.Set, we don't care
at all whether the ordering used makes any particular kind of sense;
we care only that it is consistent and total. For
semantically-meaningful comparisons, we want the semantically-correct
answer and no other.

For types with no meaningful order at all, or with a meaningful total
order that we can use, there is no ambiguity, but floating point
values have both a semantic partial order and an obvious arbitrary
total order which disagree about NaN. In the true spirit of compromise
the current Ord instance fails to implement both, ensuring that things
work incorrectly all the time rather than half the time.

That said, in lieu of introducing multiple new type classes, note that
the Haskell Report specifically describes Ord as representing a total
order[0], so the current instances for floating point values seem
completely indefensible. Since removing the instances entirely is
probably not a popular idea, the least broken solution would be to
define NaN as equal to itself and less than everything else, thus
accepting the reality of Ord as the "meaningless arbitrary total
order" type class I suggested above and leaving Haskell bereft of any
generic semantic comparisons whatsoever. Ah, pragmatism.

> As for Enum, if someone were to want a type class to represent an
> enumeration of all the values of a type, then such a thing is reasonable
> to want.  Maybe you can even reasonably wish it were called Enum.  But
> it would be the *wrong* thing to use as a desugaring for list range
> notation.  List ranges are very unlikely to be useful or even meaningful
> for most such enumerations (what is [ Red, Green .. LightPurple]?); and
> conversely, as we've seen in this thread, list ranges *are* useful in
> situations where they are not a suitable way of enumerating all values
> of a type.

It's not clear that Enum, as it stands, actually means anything coherent at all.

Consider again my example of integer (x, y) coordinates. Naively, what
would [(0, 0) .. (3, 3)] appear to mean? Why, obviously it's the
sixteen points whose coordinates range from 0 to 3, except it isn't
because Enum isn't defined on pairs and doesn't work that way anyhow.
Could we describe this range with an iteration function and a
comparison? No, because the Ord instance here is intrinsically
nonsensical. And yet, the intent is simple and useful, so why don't we
have a standard type class for it?[1] This would seem to be the
obvious, intuitive interpretation for range syntax with starting and
ending values.

To the extent that Enum can be given a coherent interpretation (which
requires ignoring many existing instances), it seems to describe types
with unary successor/predecessor operations. As such, instances for
Rational, floating point values, and the like are patently nonsensical
and really should be removed. An obvious generalization would be to
define Enum based on an "increment" operation of some sort, in which
case those instances could be defined reasonably with a default
increment of 1, which is merely dubious, rather than ridiculous. The
increment interpretation would be very natural for infinite lists
defined with open ranges and an optional step size.

Absent from the above is any interpretation of expressions like [0,2
..11], which are ill-defined anyway, as evidenced by that expression
producing lists of different lengths depending on what type is chosen
for the numeric literals. Myself, I'm content to declare that use of
range syntax a mistake in general, and insist that an unbounded range
and something like takeWhile be used instead.

- C.

[0]: See here: http://www.haskell.org/onlinereport/haskell2010/haskellch6.html#x13-1290006.3.2
[1]: Spoiler: We do.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Chris Smith-31
In reply to this post by Jake McArthur
On Tue, 2011-09-20 at 16:22 -0400, Jake McArthur wrote:
> This makes me wonder if maybe the reason this discussion is happening
> at all is that we don't have a well-defined meaning for what Enum
> *is*.

Certainly, we don't have a type-independent definition for Enum.  I'm
not sure whether it's possible to obtain that or not.  Keep in mind that
for plenty of common type classes, this is not possible.  For example,
consider Monoid.  By writing a monoid instance, you're making the rather
ridiculous claim that you are specifying *the* way to define a Monoid on
that type, when of course there are more than one, and there's no formal
way to say what that Monoid should do independent of whatever operation
happens to be most commonly used for combining values of that type.
Same for many Functor or Applicative or Monad instances.

So yes, we don't know how to define a type-independent meaning... but
I'm completely sure that it would be a mistake to start dropping useful
things from Haskell just because we're unable to put our finger on a
formalism for describing them precisely without assigning type-dependent
meanings.

> What exactly does Enum enumerate?

I'd say that just like the case with Monoid, Enum means whatever it's
most useful for it to mean with respect to some particular type.  We
could probably be a little more specific with laws that we expect the
instance to follow, such as:

    enumFromTo a b == enumFromThenTo a (succ a) b

and so on.  But it's not always possible to define a notion

> To me, the list syntax sugar looks like I'm specifying bounds, so it
> makes sense to include all values within those bounds (and honestly,
> having instances for Float, Double, and Rational sounds like a mistake,
> given this)

It's unclear to me how you get from (has bounds) to (must include
*everything* in those bounds).  I'd definitely agree that for instances
of Enum that are also instances of Ord, you'd expect (all (>= a) [a ..])
and related properties.

> What does it mean to you? What makes the
> current behavior more useful than the proposed behavior?

[...]

> You say we've seen that this behavior is useful in this thread, but
> I'm not sure what it is we have seen.

More specifically, what I said is that we've seen that list range
notation is useful in some situations where a complete enumeration of
possible values is not useful, or where such an enumeration isn't the
same one we'd hope for out of a list range.  What I meant was that we've
noticed that the current behavior on Float is incompatible with being a
complete enumeration.  I'm taking it for granted that the current
behavior on Float is useful; I honestly don't see how you could argue
with that.  People use it all the time; I used it just this morning.  Of
course it's useful.

--
Chris



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Evan Laforge
In reply to this post by Casey McCann-2
> I actually think the brokenness of Ord for floating point values is
> worse in many ways, as demonstrated by the ability to insert a value
> into a Data.Set.Set and have other values "disappear" from the set as
> a result. Getting an unexpected element in a list doesn't really seem
> as bad as silently corrupting entire data structures.

Whoah, that's scary.  What are some examples of this happening?  Does
this mean it's unsafe to store Doubles in a Map?

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Ketil Malde-5
In reply to this post by Chris Smith-31

>> You forgot "confusing"?

> I didn't forget it

Sorry, I should have written "omitted".

> perhaps we ought to ask what the cause of the confusion is.

tr.v. e·nu·mer·at·ed, e·nu·mer·at·ing, e·nu·mer·ates
  1. To count off or name one by one; list: A spokesperson enumerated the strikers' demands.
  2. To determine the number of; count.

Regardless of how easily the children you teach get it, to me
enumerating is a different thing from repeatedly adding one.

>> Expecting Enum to enumerate all inhabitants of
>> a type seems very reasonable to me, and seems to hold for all
>> non-floating point types.

> Floating point (and fixed point, for that matter) types approximate real
> numbers, which of course have no possible enumeration of all values.
  [..]
> It seems to me particularly pointless to define an Enum
> instance that focuses on, above all else, the inaccuracy of that
> approximation.

Yes.  But we need an Enum instance to get the syntactic sugar of
[1..10], so one is defined anyway.

> Perhaps I was understating the case in saying the
> behavior was established but undocumented; rather, it's explicitly
> documented in the Haskell Report.

Absolutely, it is, as I've said, the reality - like it or not.

>> Or just avoid Enum, and define "range" or something similar instead.

> If Haskell defined list syntax in terms of something that's not called
> Enum, that would be fine.  Renaming is never all that big a deal.  But
> the list sugar is a big deal, and I don't think there's any point at all
> in leaving the list sugar associated with something as minor as building
> a representation of the inaccuracy of your approximations.

I must admit I don't understand this comment.  If the fixpoint library
wants to provide the functionality (producing all values between two
points), and can't/shouldn't use Enum, surely it must provide a
different function, and let go of the list sugar?

-k
--
If I haven't seen further, it is by standing in the footprints of giants

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Evan Laforge
In reply to this post by Chris Smith-31
> complete enumeration.  I'm taking it for granted that the current
> behavior on Float is useful; I honestly don't see how you could argue
> with that.  People use it all the time; I used it just this morning.  Of
> course it's useful.

It was useful but not as useful as a 'range' function.  I thought it
was quite useful and used it even though I *already knew* about 'last
[0, 0.1 .. 2] > 2'.  But of course this eventually lead to a tricky
bug, followed by a "never again" and witch hunt for all uses of [..]
with floats :)  Maybe it's just me, but would guess that your students
would find it perfectly clear and not confusing at all... until they
found out about that little thing with 'last' above... *then* they
might be confused.

Maybe this is just an argument that Double's enumFromThenTo should use
multiplication instead of successive addition?

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: instance Enum Double considered not entirely great?

Chris Smith-31
In reply to this post by Casey McCann-2
On Tue, 2011-09-20 at 17:28 -0400, Casey McCann wrote:
> Since removing the instances entirely is
> probably not a popular idea, the least broken solution would be to
> define NaN as equal to itself and less than everything else, thus
> accepting the reality of Ord as the "meaningless arbitrary total
> order" type class I suggested above and leaving Haskell bereft of any
> generic semantic comparisons whatsoever. Ah, pragmatism.

There's nothing *wrong* with pragmatism, but in any case, we seem to
agree on this.  As I said earlier, we ought to impose a (rather
arbitrary) total order on Float and Double, and then offer comparison
with IEEE semantics as a separate set of functions when they are needed.
(I wonder if Ocaml-style (<.) and (>.) and such are used anywhere.)

> It's not clear that Enum, as it stands, actually means anything coherent at all.

It's clear to me that Enum for Float means something coherent.  If
you're looking for a meaning independent of the instance, I'd argue you
ought to be surprised if you find one, not the other way around.  Why
not look for a meaning for Monoid that's independent of the instance?
There isn't one; instead, there are some rules that the instance is
expected to satisfy, but there are plenty of types that have many
possible Monoid instances, and we pick one and leave you to use newtypes
if you wanted a different one.

I'm not saying that Enum must be left exactly as is... but I *am* saying
that the ability to use floating point types in list ranges is important
enough to save.  For all its faults, at least the current language can
do that.  When the solution to the corner cases is to remove a pervasive
and extremely useful feature, I start to get worried!

Yes, I could see (somehow in small steps that preserve backward
compatibility for reasonable periods) building some kind of clearer
relationship between Ord, Enum, and Ix, possibly separating Enum from a
new Range class that represents the desugaring of list ranges, or
whatever... but this idea of "I don't think this expresses a deep
underlying relationship independent of type, so let's just delete it
without regard to how useful it is" is very short-sighted.

--
Chris Smith



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
12345