Proposal: add conversion functions to Data.Fixed.

Hello, In my work I've run into an annoyance: Data.Fixed.Fixed does not have a Binary instance in the binary package. This is a result of the representation of Fixed being hidden, which is understandable. The problem is that when I want to create a Binary instance for Fixed, I need to use unsafeCoerce, which is nasty, and there's no built-in way to safely deal with problems involving the desired resolution being different when deseralizing. Today I played around with the source to Fixed, and came up with this proposed solution: - | Get a Fixed value's Integer representation and resolution. fromFixed :: (HasResolution a) => Fixed a -> (Integer,Integer) fromFixed f@(MkFixed i) = (i, resolution f) -- | Given an Integer representation and resolution of a Fixed value, -- create a new Fixed value with an arbitrary resolution. toFixed :: (HasResolution a) => (Integer,Integer) -> Fixed a toFixed (i,r0) = withResolution (\r1 -> MkFixed $ (i * r1) `div` r0) These functions lead to this useful derivation: convertFixed = toFixed . fromFixed, which leads to the possibility of having many possibly useful utility functions, such as toUni, fromUni, toDeci, fromDeci, etc. From fromFixed and toFixed, a safe instance for Binary (Fixed a) can be built (I haven't tested this, but it looks right): instance (HasResolution a) => Binary (Fixed a) where put = put . fromFixed get = get >>= return . toFixed Here is my patch: https://docs.google.com/open?id=0B8oSBVnQGD_wNGEtT1JRSnpPUms. Please respond with any comments, concerns, or ideas. Discussion period: 3 weeks. Thanks, Jeff

Jeff Shaw wrote:
In my work I've run into an annoyance: Data.Fixed.Fixed does not have a
Binary instance in the binary package.
Ashley Yakeley wrote:
Just to be clear, this is a modification of binary, not Data.Fixed in base, is that correct?
Hmm, I had understood just the opposite: that the proposal was to add fromFixed/toFixed to Data.Fixed, motivated by the difficulty of things like writing a Binary instance. So I hope the proposer responds soon. This proposal will not get very far unless it is completely clear what is being proposed. Thanks, Yitz

On 01/12/12 12:11, Yitzchak Gale wrote:
Jeff Shaw wrote:
In my work I've run into an annoyance: Data.Fixed.Fixed does not have a Binary instance in the binary package.
Ashley Yakeley wrote:
Just to be clear, this is a modification of binary, not Data.Fixed in base, is that correct?
Hmm, I had understood just the opposite: that the proposal was to add fromFixed/toFixed to Data.Fixed, motivated by the difficulty of things like writing a Binary instance.
Oh yes, you're right. But I don't think it's necessary. -- Ashley

To be frank, I would just rather have access to the constructor to Fixed.
It honestly strikes me as silly to have to pay for a division and/or
multiplication every time I want to access one.
There in an ideological distinction being maintained here about the one
true usage pattern that has forced me to reimplement Data.Fixed in my own
code to avoid the overhead. =(
You can bury it in an Internal module or something and load it with caveats
about how it is a bad idea to use and how you reserve the right to change
it some day, but without it Data.Fixed remains almost useless to me.
The Binary instance can trivially be implemented on top of that, as we
shoudn't be encoding type (precision) information in the Binary data stream.
-Edward
On Sat, Dec 1, 2012 at 5:54 PM, Ashley Yakeley
On 01/12/12 12:11, Yitzchak Gale wrote:
Jeff Shaw wrote:
In my work I've run into an annoyance: Data.Fixed.Fixed does not have a Binary instance in the binary package.
Ashley Yakeley wrote:
Just to be clear, this is a modification of binary, not Data.Fixed in base, is that correct?
Hmm, I had understood just the opposite: that the proposal was to add fromFixed/toFixed to Data.Fixed, motivated by the difficulty of things like writing a Binary instance.
Oh yes, you're right. But I don't think it's necessary.
-- Ashley
______________________________**_________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/**mailman/listinfo/librarieshttp://www.haskell.org/mailman/listinfo/libraries

Might as well, since we already have fromEnum and toEnum (which unfortunately convert to Int). -- Ashley On 01/12/12 18:14, Edward Kmett wrote:
To be frank, I would just rather have access to the constructor to Fixed.
It honestly strikes me as silly to have to pay for a division and/or multiplication every time I want to access one.
There in an ideological distinction being maintained here about the one true usage pattern that has forced me to reimplement Data.Fixed in my own code to avoid the overhead. =(
You can bury it in an Internal module or something and load it with caveats about how it is a bad idea to use and how you reserve the right to change it some day, but without it Data.Fixed remains almost useless to me.
The Binary instance can trivially be implemented on top of that, as we shoudn't be encoding type (precision) information in the Binary data stream.
-Edward
On Sat, Dec 1, 2012 at 5:54 PM, Ashley Yakeley
mailto:ashley@semantic.org> wrote: On 01/12/12 12:11, Yitzchak Gale wrote:
Jeff Shaw wrote:
In my work I've run into an annoyance: Data.Fixed.Fixed does not have a Binary instance in the binary package.
Ashley Yakeley wrote:
Just to be clear, this is a modification of binary, not Data.Fixed in base, is that correct?
Hmm, I had understood just the opposite: that the proposal was to add fromFixed/toFixed to Data.Fixed, motivated by the difficulty of things like writing a Binary instance.
Oh yes, you're right. But I don't think it's necessary.
-- Ashley
_________________________________________________ Libraries mailing list Libraries@haskell.org mailto:Libraries@haskell.org http://www.haskell.org/__mailman/listinfo/libraries http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Edward Kmett
To be frank, I would just rather have access to the constructor to Fixed.
It honestly strikes me as silly to have to pay for a division and/or multiplication every time I want to access one.
There in an ideological distinction being maintained here about the one true usage pattern that has forced me to reimplement Data.Fixed in my own code to avoid the overhead. =(
Fwiw, I've sometimes wanted to have 'Int' based fixed-precision arithmetic, and the current Data.Fixed allows only for "big-num" based fixed-precision types. Just a thought: Why does Data.Fixed have to be in 'base' anyway if the interface doesn't seem to be agreed upon by everyone? Can't we split it off into a separate package where it can more easily evolve into a richer API? I've done a quick head-count over the ~4600 packages on hackage w.r.t. which import Data.Fixed, and I found the 45 packages below which directly import it. So splitting Data.Fixed from 'base' would affect only about 1% of packages... Chart-0.16 collada-output-0.6 complex-generic-0.1.1 configurator-0.2.0.1 deepseq-1.3.0.1 DisTract-0.2.5 ebeats-0.1.0 esotericbot-0.0.6 fixed-point-0.5.0.1 gearbox-1.0.0.1 Geodetic-0.4 gluturtle-0.0.56 gps-1.1 GPX-0.7.0 has-0.5.0.1 haskell-platform-test-2010.2.0.0 HDBC-2.3.1.1 hsc3-0.12 husk-scheme-3.6 lambdabot-4.2.3.3 network-bitcoin-1.0.1 Noise-1.0.5 penny-lib-0.4.0.0 postgresql-simple-0.2.4.1 propane-0.1 QuickCheck-2.5.1.1 quickcheck-instances-0.3.1 random-extras-0.19 random-fu-0.2.3.1 remote-0.1.1 repr-0.4.1.3 RNAwolf-0.4.0.0 rsagl-0.6.0.1 rsagl-math-0.6.0.1 safecopy-0.7.1 sindre-0.4 tamarin-prover-0.8.2.1 time-1.4.0.1 time-http-0.5 time-lens-0.3 timeparsers-0.3.2 time-w3c-0.1.0.1 webdriver-0.4 wxturtle-0.0.1 xturtle-0.1.11 cheers, hvr

On 02/12/12 01:25, Herbert Valerio Riedel wrote:
Edward Kmett
writes: To be frank, I would just rather have access to the constructor to Fixed.
It honestly strikes me as silly to have to pay for a division and/or multiplication every time I want to access one.
There in an ideological distinction being maintained here about the one true usage pattern that has forced me to reimplement Data.Fixed in my own code to avoid the overhead. =( Fwiw, I've sometimes wanted to have 'Int' based fixed-precision arithmetic, and the current Data.Fixed allows only for "big-num" based fixed-precision types.
Just a thought: Why does Data.Fixed have to be in 'base' anyway if the interface doesn't seem to be agreed upon by everyone? Can't we split it off into a separate package where it can more easily evolve into a richer API?
+1 to both of these ideas. -- Ashley

+1 to splitting off Fixed as well.
On Sun, Dec 2, 2012 at 4:55 AM, Ashley Yakeley
On 02/12/12 01:25, Herbert Valerio Riedel wrote:
Edward Kmett
writes: To be frank, I would just rather have access to the constructor to Fixed.
It honestly strikes me as silly to have to pay for a division and/or multiplication every time I want to access one.
There in an ideological distinction being maintained here about the one true usage pattern that has forced me to reimplement Data.Fixed in my own code to avoid the overhead. =(
Fwiw, I've sometimes wanted to have 'Int' based fixed-precision arithmetic, and the current Data.Fixed allows only for "big-num" based fixed-precision types.
Just a thought: Why does Data.Fixed have to be in 'base' anyway if the interface doesn't seem to be agreed upon by everyone? Can't we split it off into a separate package where it can more easily evolve into a richer API?
+1 to both of these ideas.
-- Ashley

On Mon, Dec 03, 2012 at 10:07:32AM -0500, Edward Kmett wrote:
+1 to splitting off Fixed as well.
Note that time uses Data.Fixed, so a split-off 'fixed' package would still have to come with GHC. If splitting it off I wonder if there's anything else that would sensibly go into a 'numeric' package. Data.Ratio and Numeric are the two that come to mind, but it looks like both have a couple of uses elsewhere in base. Thanks Ian

On 07/12/12 09:15, Ian Lynagh wrote:
On Sat, Dec 01, 2012 at 09:14:28PM -0500, Edward Kmett wrote:
To be frank, I would just rather have access to the constructor to Fixed.
I would prefer this, in Data.Fixed.Internal[s], to the original proposal.
Is another module really necessary? Note that fromEnum and toEnum already expose the internal Integer, badly, as an Int. These are the changes I think we should make to Fixed: 1. Make the internal type generic, similar to Ratio/Rational. 2. Make access to the internal type easy and fast. Ratio has numerator/denominator/(%), but Ratio needs to canonicalise its values to lowest terms. Fixed doesn't need that, so exposing the constructor should serve. 3. Move Data.Fixed into a new package, possibly with Data.Ratio and perhaps other numerics stuff that can be moved out of base. 4. Move div', mod' and divmod' to a more sensible module and maybe rename them, or have them replace div, mod and divmod. I am somewhat motivated to 1 by calls to make certain time types generic, although that's a separate discussion with its own issues. -- Ashley

I would be a +1 to any or all of these changes. I, too, don't see the point
in hiding the constructor in a separate module. Like you said, the
fromEnum/toEnum instances already give away the farm.
-Edward
On Sat, Dec 8, 2012 at 12:49 AM, Ashley Yakeley
already expose the internal Integer, badly, as an Int.
These are the changes I think we should make to Fixed:
1. Make the internal type generic, similar to Ratio/Rational.
2. Make access to the internal type easy and fast. Ratio has numerator/denominator/(%), but Ratio needs to canonicalise its values to lowest terms. Fixed doesn't need that, so exposing the constructor should serve.
3. Move Data.Fixed into a new package, possibly with Data.Ratio and perhaps other numerics stuff that can be moved out of base.
4. Move div', mod' and divmod' to a more sensible module and maybe rename them, or have them replace div, mod and divmod.
I am somewhat motivated to 1 by calls to make certain time types generic, although that's a separate discussion with its own issues.

On Fri, Dec 07, 2012 at 09:49:04PM -0800, Ashley Yakeley wrote:
On 07/12/12 09:15, Ian Lynagh wrote:
On Sat, Dec 01, 2012 at 09:14:28PM -0500, Edward Kmett wrote:
To be frank, I would just rather have access to the constructor to Fixed.
I would prefer this, in Data.Fixed.Internal[s], to the original proposal.
Is another module really necessary? Note that fromEnum and toEnum already expose the internal Integer, badly, as an Int.
Exporting it from Data.Fixed would also be fine with me. Thanks Ian

On 28/11/12 09:07, Jeff Shaw wrote:
- | Get a Fixed value's Integer representation and resolution. fromFixed :: (HasResolution a) => Fixed a -> (Integer,Integer) fromFixed f@(MkFixed i) = (i, resolution f)
-- | Given an Integer representation and resolution of a Fixed value, -- create a new Fixed value with an arbitrary resolution. toFixed :: (HasResolution a) => (Integer,Integer) -> Fixed a toFixed (i,r0) = withResolution (\r1 -> MkFixed $ (i * r1) `div` r0)
How about... fromFixed f = let r = resolution f in (truncate (f * r),r) toFixed (i,r) = fromRational (i % r) -- Ashley

OK, I'm seeing consensus for the simple exposure of the constructor of the Fixed type. If we want to pursue the project of moving stuff out of base, then perhaps Data.Fixed, Data.Ratio and Data.Complex could all move to another package or separate packages. But that would be a different proposal. -- Ashley
participants (7)
-
Ashley Yakeley
-
Edward Kmett
-
Gregory Collins
-
Herbert Valerio Riedel
-
Ian Lynagh
-
Jeff Shaw
-
Yitzchak Gale