Scale by zero

47 views
Skip to first unread message

Brent Yorgey

unread,
Aug 5, 2012, 9:24:57 AM8/5/12
to diagrams...@googlegroups.com
This is a sticky issue on which I hope to get some people's thoughts.
Currently diagrams-core (in the Graphics.Rendering.Diagrams.Transform
module) contains this code:

-- | Scale uniformly in every dimension by the given scalar.
scale :: (Transformable t, Fractional (Scalar (V t)), Eq (Scalar (V t)))
=> Scalar (V t) -> t -> t
scale 0 = error "scale by zero! Halp!" -- XXX what should be done here?
scale s = transform $ scaling s

However, I think it's really unacceptable for diagrams-core to be able
to crash like this. In the past I just thought, "well, it's not too
bad... why would anyone ever scale by zero?". However, yesterday
mgsloan and I were playing with his diagrams-ghci project [1] and we
had something like

foo # scale 20

and wanted to edit the scaling factor... and we happened to delete the
'2' first, but since it's live-updating it immediately sent 'foo #
scale 0' to the backend and the whole application promptly crashed.

The point is there are any number of legitimate or accidental reasons
this kind of thing could happen and the core library simply should not
crash, ever.

So, how to fix this? Possible solutions include:

* scale 0 is the identity function

* add a Monoid t constraint to scale, and set scale 0 = mempty

* add an 'empty' method to the Transformable class, and set scale 0
= empty

I can see pros and cons to each of these solutions, but instead of
saying what I think, I'd like to hear what others think -- and
especially if you have any other ideas for solving this issue.

-Brent

[1] https://github.com/mgsloan/diagrams-ghci

Felipe Almeida Lessa

unread,
Aug 5, 2012, 10:50:52 AM8/5/12
to diagrams...@googlegroups.com
On Sun, Aug 5, 2012 at 10:24 AM, Brent Yorgey <byo...@seas.upenn.edu> wrote:
> and wanted to edit the scaling factor... and we happened to delete the
> '2' first, but since it's live-updating it immediately sent 'foo #
> scale 0' to the backend and the whole application promptly crashed.
>
> The point is there are any number of legitimate or accidental reasons
> this kind of thing could happen and the core library simply should not
> crash, ever.

While I agree that diagrams should never crash, diagrams-ghci should
also catch exceptions =).

> So, how to fix this? Possible solutions include:
>
> * scale 0 is the identity function

This is extremely counter-intuitive for me. Intuitively I'd like
'scale 0' to be the "limit diagram" of the sequence 'scale 1', 'scale
0.1', 'scale 0.01'...

> * add a Monoid t constraint to scale, and set scale 0 = mempty
>
> * add an 'empty' method to the Transformable class, and set scale 0
> = empty

I'm not sure which would be better, but AFAICS both would appease to
my intuition =).

Cheers,

--
Felipe.

Stephen Tetley

unread,
Aug 5, 2012, 5:01:22 PM8/5/12
to diagrams...@googlegroups.com
In PostScript (GhostScript) scaling by zero draws an empty figure - so
either 2 or 3 would match this. Option 1 seems wrong geometrically.

Michael Sloan

unread,
Aug 5, 2012, 5:12:45 PM8/5/12
to Stephen Tetley, diagrams...@googlegroups.com
True, diagrams-ghci should catch exceptions. It may be my lack of
exception-foo, but even wrapping things in `catchError` in multiple
locations couldn't catch this. It might work to send code to the
interpreter that is wrapped in the catchError, but there really
shouldn't be a distinction between catching in the interpreter and
outside it, since you can "interpret" functions and evaluate them
externally.

While we are not very breakage averse, adding the Monoid constrant
would lead to a lot more changes, and generally add more constraints
on things. So, I guess my vote is for adding something like "empty"
to Transformable. Maybe we want to make it dependent on the previous
value? Some things might not have a static way of "disappearing
things", so maybe "disappear :: a -> a".

Maybe make this guy a superclass of Transformable? In the past, when
working on commutative-replicated-data-types, I've wanted something
like "Zeroable" - has some zero representation, but the datastructure
persists some critical history.

If this approach is taken, then there should be a comment in the code
about eventually using -XDefaultSignatures to give one in terms of
Monoid.

-Michael

Felipe Almeida Lessa

unread,
Aug 5, 2012, 5:24:33 PM8/5/12
to Michael Sloan, Stephen Tetley, diagrams...@googlegroups.com
On Sun, Aug 5, 2012 at 6:12 PM, Michael Sloan <mgs...@gmail.com> wrote:
> True, diagrams-ghci should catch exceptions. It may be my lack of
> exception-foo, but even wrapping things in `catchError` in multiple
> locations couldn't catch this. It might work to send code to the
> interpreter that is wrapped in the catchError, but there really
> shouldn't be a distinction between catching in the interpreter and
> outside it, since you can "interpret" functions and evaluate them
> externally.

I'd probably try catching this exception when drawing with cairo,
since that's the only time when everything is guaranteed to be forced.
Have you tried that? =)

Cheers,

--
Felipe.

John Lato

unread,
Aug 5, 2012, 8:38:07 PM8/5/12
to diagrams...@googlegroups.com
Sorry, sent this to just Michael originally...

I also think "empty" is a good approach. Unless I'm missing your
intention, I don't think adding a Monoid constraint would be helpful.
Considering two monoids that are likely to be used (or at least
tried), Sum and Prod, neither one would lead to desirable behavior.

John L.
Reply all
Reply to author
Forward
0 new messages