<div>Hi All,</div><div><br></div>Here&#39;s what I have so far:<div>I haven&#39;t tried it with monoids but I&#39;m intrigued...</div><div><br></div><div><br></div><div><div><div>data Measure = M Volume Float</div><div>  deriving (Show, Eq)</div>
<div><br></div><div>data Volume = Teaspoon</div><div>            | Tablespoon</div><div>            | FluidOunce</div><div>            | Slice</div><div>  deriving (Show, Eq, Ord, Bounded)                                  -- Note the Ord and Bounded typeclasses</div>
<div><br></div><div><br></div><div><br></div><div>stepDown :: Measure -&gt; Measure                                      -- stepDown - convert Measures to one unit smaller</div><div>stepDown (M Slice a)      = M FluidOunce (a * 120)</div>
<div>stepDown (M FluidOunce a) = M Tablespoon (a * 2)</div><div>stepDown (M Tablespoon a) = M Teaspoon (a * 3)</div><div>stepUp   (M Teaspoon a)   = M Tablespoon (a / 3)              -- stepUp - convert Measures to one unit larger</div>
<div>stepUp   (M Tablespoon a) = M FluidOunce (a / 2)</div><div>stepUp   (M FluidOunce a) = M Slice (a / 120)</div><div>stepUp   (M Slice a)      = M Slice (a * 1)</div><div><br></div><div><br></div><div>convertDown :: Measure -&gt; Volume -&gt; Measure                 -- stepDown multiple times, to a desired unit</div>
<div>convertDown (M unit measure) goalUnit</div><div>                     | unit == goalUnit = M unit measure</div><div>                     | otherwise        = convertDown (stepDown (M unit measure))  goalUnit</div><div>
<br></div><div>convertUp all@(M unit measure)                                      -- stepUp to a unit which &quot;makes sense&quot; for the magnitude of the measure</div><div>            | (measure &gt; 25) &amp;&amp; (unit /= (maxBound :: Volume)) = convertUp $ stepUp all</div>
<div>            | otherwise    = all</div><div><br></div><div><br></div><div>(&lt;+&gt;) :: Measure -&gt; Measure -&gt; Measure                        -- do the addition</div><div>a@(M unitA measureA) &lt;+&gt; b@(M unitB measureB)</div>
<div>     | unitA == unitB = M unitA (measureA + measureB)</div><div>     | unitA &gt; unitB  = convertUp $ ((convertDown a unitB) &lt;+&gt; b)</div><div>     | unitA &lt; unitB  = convertUp $ (a &lt;+&gt; (convertDown b unitA))</div>
</div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div>This is fully functional:</div><div><div>*Main&gt; (M Slice 30) &lt;+&gt; (M Teaspoon 3)</div><div>M Slice 30.004168</div><div><div>*Main&gt; (M FluidOunce 57) &lt;+&gt; (M Slice 0.2)</div>
<div>M Slice 0.675</div><div><div>*Main&gt; stepDown it</div><div>M FluidOunce 81.0</div><div><br></div></div><div><br></div><div>etc.</div><div><br></div><div><br></div><div><br></div><div><br></div><div>In convertUp, &quot;25&quot; could be replaced by a multiple of the unit &quot;above&quot; if I had a better data structure for keeping track of conversion amounts.</div>
<div>This is the major kludge that I see in my code right now. Having one stepUp function and one stepDown function, each of which read off a conversion list, or even some type of tree, would be more efficient.</div><div>
<br></div><div><br></div><div>Any resources, for solutions to this problem, would definitely be appreciated.</div><div>Again, I&#39;m really surprised that I can&#39;t find very much at all, on what seems to be a common computing problem.</div>
<div><br></div><div>Thanks for your time.</div><div><br></div><div>Tom</div><div><br></div><div><br></div><div><br></div></div></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div>
<div><br></div><div><br></div><br><div class="gmail_quote">On Sat, Mar 19, 2011 at 12:11 AM, aditya siram <span dir="ltr">&lt;<a href="mailto:aditya.siram@gmail.com">aditya.siram@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
How about something like this?<br>
<br>
import Data.Monoid<br>
<div class="im"><br>
data Volumes = Teaspoon | Tablespoon | Slice | FluidOunces<br>
</div>type Quantity = (Int, Volumes)<br>
<br>
instance Monoid Quantity where<br>
    mempty = (0, Teaspoon)<br>
    mappend a b = ((toTeaspoon a) + (toTeaspoon b), Teaspoon)<br>
<br>
toTeaspoon :: Quantity -&gt; Int<br>
toTeaspoon (a, Teaspoon) = a<br>
toTeaspoon (a, Tablespoon) = undefined<br>
toTeaspoon (a, Slice) = undefined<br>
toTeaspoon (a, FluidOunces) = undefined<br>
<br>
-deech<br>
<div><div></div><div class="h5"><br>
On Fri, Mar 18, 2011 at 10:02 PM, Tom Murphy &lt;<a href="mailto:amindfv@gmail.com">amindfv@gmail.com</a>&gt; wrote:<br>
&gt; On Fri, Mar 18, 2011 at 5:02 AM, Magnus<br>
&gt; Therning &lt;<a href="mailto:magnus@therning.org">magnus@therning.org</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; On Thu, Mar 17, 2011 at 21:17, Tom Murphy &lt;<a href="mailto:amindfv@gmail.com">amindfv@gmail.com</a>&gt; wrote:<br>
&gt;&gt; &gt; Hi All,<br>
&gt;&gt; &gt;      Is there a good way to easily convert between units?<br>
&gt;&gt; &gt;      For example, let&#39;s say I have a data type:<br>
&gt;&gt; &gt;      data Volumes = Teaspoon | Tablespoon | Slice | FluidOunces<br>
&gt;&gt; &gt;      ... and I want to define an infix function &#39;&lt;+&gt;&#39;, which adds<br>
&gt;&gt; &gt; together<br>
&gt;&gt; &gt; amounts of food:<br>
&gt;&gt; &gt;      (1, Slice, cake) &lt;+&gt; (1, Volume Tablespoon, sugar) &lt;+&gt; (32, Volume<br>
&gt;&gt; &gt; FluidOunces, almondMilk)<br>
&gt;&gt; &gt;      Which would return:<br>
&gt;&gt; &gt;      (3200, Teaspoons)<br>
&gt;&gt; &gt;      What is the most efficient way to define equivalency/conversion<br>
&gt;&gt; &gt; between<br>
&gt;&gt; &gt; these measures?<br>
&gt;&gt; &gt;      I remember an interesting method for celsius-farenheit conversion<br>
&gt;&gt; &gt; in<br>
&gt;&gt; &gt; Higher-Order Perl, using function composition, but that was between only<br>
&gt;&gt; &gt; 2<br>
&gt;&gt; &gt; units. I&#39;d like something where I don&#39;t have to provide n^2 definitions.<br>
&gt;&gt;<br>
&gt;&gt; I wrote two blog posts on something that sounds related:<br>
&gt;&gt; <a href="http://therning.org/magnus/archives/354" target="_blank">http://therning.org/magnus/archives/354</a><br>
&gt;&gt; <a href="http://therning.org/magnus/archives/355" target="_blank">http://therning.org/magnus/archives/355</a><br>
&gt;&gt;<br>
&gt;&gt; Maybe they could help.<br>
&gt;&gt;<br>
&gt;&gt; /M<br>
&gt;&gt;<br>
&gt;&gt; --<br>
&gt;&gt; Magnus Therning                      OpenPGP: 0xAB4DFBA4<br>
&gt;&gt; email: <a href="mailto:magnus@therning.org">magnus@therning.org</a>   jabber: <a href="mailto:magnus@therning.org">magnus@therning.org</a><br>
&gt;&gt; twitter: magthe               <a href="http://therning.org/magnus" target="_blank">http://therning.org/magnus</a><br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt; So given<br>
&gt; data Measure = M Volume Float<br>
&gt;   deriving (Show, Eq)<br>
&gt; data Volume = Slice<br>
&gt;             | FluidOunce<br>
&gt;             | Tablespoon<br>
&gt;             | Teaspoon<br>
&gt;   deriving (Show, Eq)<br>
&gt; Method one and two would be to convert all units to the smallest unit:<br>
&gt; toTsp                           :: Measure -&gt; Measure<br>
&gt; [...]<br>
&gt; toTsp (M Slice a)          = M Teaspoon (a * 350)<br>
&gt; toTsp (M FluidOunce a) = M Teaspoon (a * 34)<br>
&gt; [...]<br>
&gt; Perform the addition, then convert it to a more appropriate measure (back to<br>
&gt; Cake Slices...).<br>
&gt;      It seems that there&#39;s a potential loss of precision, if I have to for<br>
&gt; example convert Megaliter measures to Teaspoons.<br>
&gt;<br>
&gt; Method three involves using typeclasses to define common &quot;meeting points&quot;<br>
&gt; for the units.<br>
&gt; So, we say that if we&#39;re adding Slices and FluidOunces, both measures should<br>
&gt; be converted to FluidOunces before the addition.<br>
&gt; The problem there is that, given n measurement units, we have to declare n^2<br>
&gt; typeclass instances by hand.<br>
&gt;<br>
&gt; Another way that I can see to do this is to define a &quot;chain&quot; of conversions.<br>
&gt; I&#39;d then &quot;convert down&quot; only to the smallest-common unit.<br>
&gt; So I could define<br>
&gt; (warning: extreme kludge ahead)<br>
&gt; a series of &quot;step-down&quot;s and &quot;step-up&quot;s:<br>
&gt; Given a largest-to-smallest ordering of Slice, FluidOunce, Tablespoon,<br>
&gt; Teaspoon, I can define:<br>
&gt; stepDown                           :: Measure -&gt; Measure<br>
&gt; stepDown (M Slice a)          = M FluidOunce (a * 120)<br>
&gt; stepDown (M FluidOunce a) = M Tablespoon (a * 2)<br>
&gt; stepUp   (M FluidOunce a)   = M Slice (a / 120)<br>
&gt; stepUp   (M Tablespoon a)   = M FluidOunce (a / 2)<br>
&gt; [...]<br>
&gt;<br>
&gt; and then a function to &quot;step&quot; as far down as needed:<br>
&gt; convertDown :: Measure -&gt; Volume -&gt; Measure<br>
&gt; convertDown (M unit measure) goalUnit<br>
&gt;                      | unit == goalUnit = M unit measure<br>
&gt;                      | otherwise        = fun5 (stepDown (M unit measure))<br>
&gt;  goalUnit<br>
&gt;<br>
&gt;<br>
&gt; And then if I wanted to add a Slice of cake to a Tablespoon of almond milk,<br>
&gt; I&#39;d have to find the smaller unit, convert down, perform the math and then<br>
&gt; do a &quot;convert up&quot; operation.<br>
&gt; An added benefit to this method is that defining a unit smaller than the<br>
&gt; current smallest wouldn&#39;t involve revising the &quot;base unit&quot; measures.<br>
&gt; This seems like a pretty common C.S. problem; I&#39;m surprised I haven&#39;t been<br>
&gt; able to find more resources about it.<br>
&gt; Thanks for your time!<br>
&gt; Tom<br>
&gt; P.S. Thank you, Magnus, for those resources!<br>
</div></div>&gt; _______________________________________________<br>
&gt; Beginners mailing list<br>
&gt; <a href="mailto:Beginners@haskell.org">Beginners@haskell.org</a><br>
&gt; <a href="http://www.haskell.org/mailman/listinfo/beginners" target="_blank">http://www.haskell.org/mailman/listinfo/beginners</a><br>
&gt;<br>
&gt;<br>
</blockquote></div><br></div>