[Haskell-beginners] Unit conversion
aditya.siram at gmail.com
Sat Mar 19 05:11:22 CET 2011
How about something like this?
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
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:
>> Maybe they could help.
>> 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))
> 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!
> P.S. Thank you, Magnus, for those resources!
> Beginners mailing list
> Beginners at haskell.org
More information about the Beginners