Created
October 3, 2014 23:22
-
-
Save avieth/89bccea8060dbf30272b to your computer and use it in GitHub Desktop.
RE: adding energy and torque
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- This is in response to Robert Smallshire's talk titled | |
-- 'The Unreasonable Effectiveness of Dynamic Typing for Practical Programs'. | |
-- http://www.infoq.com/presentations/dynamic-static-typing/ | |
-- Around the 30 minute mark he gives an example of what he calls a failure | |
-- of the F# type system, because it allows him to add energy to torque. | |
-- I demonstrate here that Haskell's type system is capable of ruling | |
-- out this nonsense. I have no experience with F#; maybe its type system | |
-- can do the same, if appropriately handled. | |
-- We'll need some multiparameter typeclasses. | |
{-# LANGUAGE MultiParamTypeClasses #-} | |
-- This one is just for convenience, to derive the Num instances | |
-- of our units. | |
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | |
-- We start with a predicate to identify Doubles with a unit. | |
class Unit a where | |
forgetUnit :: a -> Double | |
-- We'll want to do inter-unit multiplication, distance by force for | |
-- example, so we describe a ternary relationship for units which can | |
-- be multiplied. | |
class (Unit a, Unit b, Unit c) => CompatibleUnits a b c where | |
(|*|) :: a -> b -> c | |
-- We choose metres as our unit of distance. | |
newtype Distance = Metres Double deriving (Num, Eq, Ord, Show) | |
instance Unit Distance where | |
forgetUnit (Metres x) = x | |
-- We choose Newtons as our unit of force. | |
newtype Force = Newtons Double deriving (Num, Eq, Ord, Show) | |
instance Unit Force where | |
forgetUnit (Newtons x) = x | |
-- We choose Joules as our unit of energy. | |
newtype Energy = Joules Double deriving (Num, Eq, Ord, Show) | |
instance Unit Energy where | |
forgetUnit (Joules x) = x | |
-- Here we witness the fact that force * distance can determine energy. | |
instance CompatibleUnits Force Distance Energy where | |
x |*| y = Joules $ forgetUnit x * forgetUnit y | |
-- We choose Newton-metres as our unit of torque. | |
newtype Torque = NewtonMetres Double deriving (Num, Eq, Ord, Show) | |
instance Unit Torque where | |
forgetUnit (NewtonMetres x) = x | |
-- Here we witness the fact that force * distance can determine torque. | |
instance CompatibleUnits Force Distance Torque where | |
x |*| y = NewtonMetres $ forgetUnit x * forgetUnit y | |
-- Now, on to the tail-end of Mr. Smallshire's example. | |
-- Push a truck | |
d_truck = Metres 30.0 | |
f_truck = Newtons 20000.0 | |
-- Must help the type checker with a little hint. | |
energy_truck :: Energy | |
energy_truck = f_truck |*| d_truck | |
-- Undo a nut | |
f_spanner = Newtons 200.0 | |
d_spanner = Metres 0.2 | |
-- Again, we must disambiguate. | |
torque_spanner :: Torque | |
torque_spanner = f_spanner |*| d_spanner | |
-- The universe implodes? | |
-- Nope, GHC won't allow it. | |
wtf = energy_truck + torque_spanner |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment