Safe Haskell | None |
---|
Here we use dynamic-object
to descibe the concept of point-like particles from
classical mechanics. Also read the HSpec tests :
https://github.com/nushio3/dynamic-object/blob/master/test/ObjectSpec.hs
for more details.
- data Vec a = Vec a a
- data Mass = Mass
- data Velocity = Velocity
- data Momentum = Momentum
- data KineticEnergy = KineticEnergy
- mass :: MemberLens o Mass
- velocity :: MemberLens o Velocity
- momentum :: (UseReal o, Fractional (UnderlyingReal o)) => MemberLens o Momentum
- kineticEnergy :: (UseReal o, Fractional (UnderlyingReal o)) => MemberLens o KineticEnergy
- fromMassVelocity :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => real -> Vec real -> o
- fromMassMomentum :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => real -> Vec real -> o
- laserBeam :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => o
- duck :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => o
- lens :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => o
- banana :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => o
- envelope :: (Objective o, UseReal o, UseString o, Fractional (UnderlyingReal o), IsString (UnderlyingString o)) => o
- ghost :: Objective o => o
Documentation
First, let us create a tiny two-dimensional vector class.
We make it an instance of Arbitrary
to use them later for tests.
Vec a a |
Now, let us introduce the concepts of Mass
, Velocity
,
Momentum
and KineticEnergy
. Any such concepts are described
in terms of Member
labels.
To define a member with compound types like vector of real numbers,
we use UnderlyingReal
to
ask the object which real value it prefers, then put the response
into the type constructors.
We also give a fallback accessor here. If the velocity
field is missing, we attempt to re-calculate it
from the mass
and momentum
. Here is how we can do that.
data KineticEnergy Source
kineticEnergy
, unless given explicitly, is defined in terms of mass
and velocity
.
Typeable KineticEnergy | |
(Typeable KineticEnergy, Typeable (ValType o KineticEnergy), Objective o, UseReal o, Fractional (UnderlyingReal o)) => Member o KineticEnergy |
mass :: MemberLens o MassSource
Now we define the lenses.
momentum :: (UseReal o, Fractional (UnderlyingReal o)) => MemberLens o MomentumSource
kineticEnergy :: (UseReal o, Fractional (UnderlyingReal o)) => MemberLens o KineticEnergySource
fromMassVelocity :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => real -> Vec real -> oSource
We can write functions that would construct a point particle from its mass and velocity. And we can make the function polymorphic over the representation of the real numbers the objects prefer.
fromMassMomentum :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => real -> Vec real -> oSource
We can also construct a point particle from its mass and momentum.
laserBeam :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => oSource
We define an instance of point-like particle. And again, we can keep it polymorphic, so that anyone can choose its concrete type later, according to their purpose. Thus we will achieve the polymorphic encoding of the knowledge of this world, in Haskell.
>>>
(laserBeam :: Object DIT) ^? kineticEnergy
Just 1631.25>>>
(laserBeam :: Object Precise) ^? kineticEnergy
Just (6525 % 4)
Moreover, we can ask Ichiro to sign the ball. Usually, we needed to create a new data-type to add a new field. But with 'dynamic-object' we can do so without changing the type of the ball. So, we can put our precious, one-of-a-kind ball into toybox together with less uncommon balls, and with various other toys. And still, we can safely access the contents of the toybox without runtime errors, and e.g. see which toy is the heaviest.
>>>
let (mySpecialBall :: Object DIT) = laserBeam & insert Autograph "Ichiro Suzuki"
>>>
let toybox = [laserBeam, mySpecialBall]
>>>
let toybox2 = toybox ++ [duck, lens, banana, envelope, ghost]
>>>
maximum $ mapMaybe (^?mass) toybox2
5.2
duck :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => oSource
lens :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => oSource
banana :: (Objective o, UseReal o, Fractional real, real ~ UnderlyingReal o) => oSource
envelope :: (Objective o, UseReal o, UseString o, Fractional (UnderlyingReal o), IsString (UnderlyingString o)) => oSource