safe versions of pred and succ?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

safe versions of pred and succ?

Graham Gill
Suppose I have a function

f :: (Enum a) => a -> ...
f x ... = ...pred x ...

If a is also an instance of Bounded, then I get a runtime error if pred
minBound is evaluated during evaluation of f.

If I try to protect the use of pred x with a check using minBound, then
I have to add a Bounded constraint on type a, which would mean, for
example, that I can no longer use f with type Integer.

Do I need two different versions of f, one for Bounded a and one for
non-Bounded a? Is there a more elegant way to take care of this problem?
I don't know much about all of the type magic available in GHC.

For example, from another list message,

groupConsecutive :: (Enum a,Eq a) => [a] -> [[a]]
groupConsecutive = foldr go []
     where go x ls@(hd@(y:_):yss)
             | x == y || x == pred y = (x:hd):yss
             | otherwise             = [x]:ls
           go x [] = [[x]]

 > groupConsecutive [1,2,3,7,8,10,11,12]
[[1,2,3],[7,8],[10,11,12]]

 > groupConsecutive ([1,0,1,2]::[Word])
*** Exception: Enum.pred{Word}: tried to take `pred' of minBound

In the first go case, if type a is also Bounded, y == minBound and x /=
y, then we know already that x /= pred y, we want the guard to fail and
that we pass to the otherwise guard to start a new sublist. But how to
implement it without making the function unavailable for un-Bounded types?

Graham


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: safe versions of pred and succ?

Michael Orlitzky
On 01/14/2017 02:35 AM, Graham Gill wrote:
>
> Do I need two different versions of f, one for Bounded a and one for
> non-Bounded a? Is there a more elegant way to take care of this problem?
> I don't know much about all of the type magic available in GHC.
>

You probably want your own typeclass instead of Enum, even if it means
generating a bunch of very boring instances of it for the types you want
"f" to work on.

The fact that "pred" should throw a runtime error on "minBound" is a
documented fact of the Enum typeclass, and you should stay far far away
from such things in your own code. Besides that, there's a weird
interaction between the semantic meaning of Enum and Bounded. For
example, here's a perfectly valid enumeration of boolean values:

  True, False, True, False, ...

In your case it would be fine to have (pred False) == True, but instead
you get a runtime error thanks to the Bounded instance. So being Bounded
rules out some otherwise valid (and fine for your purposes) Enum instances.

Your "f" should also work on a singleton type:

  ghci> data Foo = Foo deriving (Eq,Show)
  ghci> instance Enum Foo where toEnum _ = Foo; fromEnum _ = 0;
  ghci> groupConsecutive [Foo,Foo,Foo,Foo]
  [[Foo,Foo,Foo,Foo]]

But any Bounded instance for Foo would mess that up. Basically, the
pre-existing Enum instances aren't exactly what you want.

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: safe versions of pred and succ?

Graham Gill
Thanks very much for that clear reply Michael.

I don't have an application in mind specifically, the example function groupConsecutive just came up in another message and set me wondering: if I have a function to work on types of class A, but types that are instances of both class A and class B are problematic, is there a way to distinguish the cases? As you say, it's probably not class A that I want my function to work over, but instead my own type class.

Graham

On 15 Jan 2017 14:09, "Michael Orlitzky" <[hidden email]> wrote:
On 01/14/2017 02:35 AM, Graham Gill wrote:
>
> Do I need two different versions of f, one for Bounded a and one for
> non-Bounded a? Is there a more elegant way to take care of this problem?
> I don't know much about all of the type magic available in GHC.
>

You probably want your own typeclass instead of Enum, even if it means
generating a bunch of very boring instances of it for the types you want
"f" to work on.

The fact that "pred" should throw a runtime error on "minBound" is a
documented fact of the Enum typeclass, and you should stay far far away
from such things in your own code. Besides that, there's a weird
interaction between the semantic meaning of Enum and Bounded. For
example, here's a perfectly valid enumeration of boolean values:

  True, False, True, False, ...

In your case it would be fine to have (pred False) == True, but instead
you get a runtime error thanks to the Bounded instance. So being Bounded
rules out some otherwise valid (and fine for your purposes) Enum instances.

Your "f" should also work on a singleton type:

  ghci> data Foo = Foo deriving (Eq,Show)
  ghci> instance Enum Foo where toEnum _ = Foo; fromEnum _ = 0;
  ghci> groupConsecutive [Foo,Foo,Foo,Foo]
  [[Foo,Foo,Foo,Foo]]

But any Bounded instance for Foo would mess that up. Basically, the
pre-existing Enum instances aren't exactly what you want.

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Loading...