[Haskell-beginners] Unit conversion

aditya siram aditya.siram at gmail.com
Sat Mar 19 05:11:22 CET 2011


How about something like this?

import Data.Monoid

data Volumes = Teaspoon | Tablespoon | Slice | FluidOunces
type Quantity = (Int, Volumes)

instance Monoid Quantity where
    mempty = (0, Teaspoon)
    mappend a b = ((toTeaspoon a) + (toTeaspoon b), Teaspoon)

toTeaspoon :: Quantity -> Int
toTeaspoon (a, Teaspoon) = a
toTeaspoon (a, Tablespoon) = undefined
toTeaspoon (a, Slice) = undefined
toTeaspoon (a, FluidOunces) = undefined

-deech

On Fri, Mar 18, 2011 at 10:02 PM, Tom Murphy <amindfv at gmail.com> wrote:
> On Fri, Mar 18, 2011 at 5:02 AM, Magnus
> Therning <magnus at therning.org> wrote:
>>
>> On Thu, Mar 17, 2011 at 21:17, Tom Murphy <amindfv at gmail.com> wrote:
>> > Hi All,
>> >      Is there a good way to easily convert between units?
>> >      For example, let's say I have a data type:
>> >      data Volumes = Teaspoon | Tablespoon | Slice | FluidOunces
>> >      ... and I want to define an infix function '<+>', which adds
>> > together
>> > amounts of food:
>> >      (1, Slice, cake) <+> (1, Volume Tablespoon, sugar) <+> (32, Volume
>> > FluidOunces, almondMilk)
>> >      Which would return:
>> >      (3200, Teaspoons)
>> >      What is the most efficient way to define equivalency/conversion
>> > between
>> > these measures?
>> >      I remember an interesting method for celsius-farenheit conversion
>> > in
>> > Higher-Order Perl, using function composition, but that was between only
>> > 2
>> > units. I'd like something where I don't have to provide n^2 definitions.
>>
>> I wrote two blog posts on something that sounds related:
>> http://therning.org/magnus/archives/354
>> http://therning.org/magnus/archives/355
>>
>> Maybe they could help.
>>
>> /M
>>
>> --
>> Magnus Therning                      OpenPGP: 0xAB4DFBA4
>> email: magnus at therning.org   jabber: magnus at therning.org
>> twitter: magthe               http://therning.org/magnus
>
>
>
>
> So given
> data Measure = M Volume Float
>   deriving (Show, Eq)
> data Volume = Slice
>             | FluidOunce
>             | Tablespoon
>             | Teaspoon
>   deriving (Show, Eq)
> Method one and two would be to convert all units to the smallest unit:
> toTsp                           :: Measure -> Measure
> [...]
> toTsp (M Slice a)          = M Teaspoon (a * 350)
> toTsp (M FluidOunce a) = M Teaspoon (a * 34)
> [...]
> Perform the addition, then convert it to a more appropriate measure (back to
> Cake Slices...).
>      It seems that there's a potential loss of precision, if I have to for
> example convert Megaliter measures to Teaspoons.
>
> Method three involves using typeclasses to define common "meeting points"
> for the units.
> So, we say that if we're adding Slices and FluidOunces, both measures should
> be converted to FluidOunces before the addition.
> The problem there is that, given n measurement units, we have to declare n^2
> typeclass instances by hand.
>
> Another way that I can see to do this is to define a "chain" of conversions.
> I'd then "convert down" only to the smallest-common unit.
> So I could define
> (warning: extreme kludge ahead)
> a series of "step-down"s and "step-up"s:
> Given a largest-to-smallest ordering of Slice, FluidOunce, Tablespoon,
> Teaspoon, I can define:
> stepDown                           :: Measure -> Measure
> stepDown (M Slice a)          = M FluidOunce (a * 120)
> stepDown (M FluidOunce a) = M Tablespoon (a * 2)
> stepUp   (M FluidOunce a)   = M Slice (a / 120)
> stepUp   (M Tablespoon a)   = M FluidOunce (a / 2)
> [...]
>
> and then a function to "step" as far down as needed:
> convertDown :: Measure -> Volume -> Measure
> convertDown (M unit measure) goalUnit
>                      | unit == goalUnit = M unit measure
>                      | otherwise        = fun5 (stepDown (M unit measure))
>  goalUnit
>
>
> And then if I wanted to add a Slice of cake to a Tablespoon of almond milk,
> I'd have to find the smaller unit, convert down, perform the math and then
> do a "convert up" operation.
> An added benefit to this method is that defining a unit smaller than the
> current smallest wouldn't involve revising the "base unit" measures.
> This seems like a pretty common C.S. problem; I'm surprised I haven't been
> able to find more resources about it.
> Thanks for your time!
> Tom
> P.S. Thank you, Magnus, for those resources!
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>



More information about the Beginners mailing list