-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUnits.hs
145 lines (110 loc) · 5.91 KB
/
Units.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
{-# LANGUAGE
GADTs,
MultiParamTypeClasses,
TypeSynonymInstances,
FunctionalDependencies,
FlexibleInstances,
FlexibleContexts,
UndecidableInstances
#-}
-- NOTE - This module isn't even used in this project. This was an experimental
-- next move that I was overzealously planning while I was playing with
-- typeclasses. Looking back years later, it probably adds no value to this
-- program so I will probably delete it, but I will doublecheck first.
module Units where
-- The nature of units
class (Num num_type) => Unit unit_type num_type | unit_type -> num_type where
__ :: num_type -> (UnitValue unit_type num_type)
__ = UnitValue
type SafeValue = Float -- This will be a re-definition when we bring it back to the other code, so remove it then.
data UnitValue unit_type num_type where
UnitValue :: (Unit unit_type num_type, Num num_type) => num_type -> UnitValue unit_type num_type
-- The nature of sorts of units
-- Order of operations
infixr 6 +:
infixr 7 *:
infixr 7 /:
-- Starting off with Progressions, with (+:), but we can have various functions over time that operate on Progressions,
-- since they'd be used as a marker of how far along a list of items (samples, etc).
class (Unit u num_type) => Progression u num_type where
__dummy :: u -> u
-- Not implemented as a typeclass function because it works on Units the same way
(+:) :: (Progression unit_type num_type) => UnitValue unit_type num_type-> UnitValue unit_type num_type -> UnitValue unit_type num_type
(+:) (UnitValue a) (UnitValue b) = UnitValue (a + b)
-- Next with how units interoperate.
class (Num t_num, Num b_num, Num r_num, Unit top t_num, Unit bottom b_num, Unit result r_num, UnitRelationshipDefault t_num b_num r_num)
=> UnitRelationship top bottom result t_num b_num r_num | top bottom -> result, top -> t_num, bottom -> b_num, result -> r_num where
(*:) :: UnitValue bottom b_num -> UnitValue result r_num -> UnitValue top t_num
(*:) (UnitValue a) (UnitValue b) = UnitValue $ default_mult a b
(/:) :: UnitValue top t_num -> UnitValue bottom b_num -> UnitValue result r_num
(/:) (UnitValue a) (UnitValue b) = UnitValue $ default_div a b
class (Num t_num, Num b_num, Num r_num) => UnitRelationshipDefault t_num b_num r_num where
default_mult :: b_num -> r_num -> t_num
default_div :: t_num -> b_num -> r_num
instance UnitRelationshipDefault SafeValue SafeValue SafeValue where
default_mult b r = b * r
default_div t b = t / b
instance UnitRelationshipDefault SafeValue SafeValue Integer where
default_mult b r = b * (fromIntegral r)
default_div t b = floor $ t / b
instance UnitRelationshipDefault SafeValue Integer SafeValue where
default_mult b r = (fromIntegral b) * r
default_div t b = t / (fromIntegral b)
instance UnitRelationshipDefault Integer Integer SafeValue where
default_mult b r = floor $ (fromIntegral b) * r
default_div t b = (fromIntegral t) / (fromIntegral b)
instance UnitRelationshipDefault Integer SafeValue Integer where
default_mult b r = floor $ b * (fromIntegral r)
default_div t b = floor $ (fromIntegral t) / b
-- Actual unit types and their interactions:
-- (Notes)
-- TimeSamplingRate = TimeSamples/Time
-- Frequency = NumCycles/Time
-- Time * Frequency = NumCycles
-- Time * SamplingRate = Samples
-- CycleSamplingRate = CycleSamples/NumCycles
data Hertz = Hertz
data Cycle = Cycle
data Second = Second
data Sample = Sample
data Amplitude = Amplitude
data SignalValue = SignalValue
data SignalSlope = SignalSlope
data SamplePerSecond = SamplePerSecond
-- Some shortcuts, since the type of __ aka UnitValue is ambiguous, and Hertz etc are only a parameter.
-- Would be nice if these were automatically made
_second = __ :: SafeValue -> UnitValue Second SafeValue
_sample = __ :: Integer -> UnitValue Sample Integer
_cycle = __ :: SafeValue -> UnitValue Cycle SafeValue
_hertz = __ :: SafeValue -> UnitValue Hertz SafeValue
_amplitude = __ :: SafeValue -> UnitValue Amplitude SafeValue
_signalvalue = __ :: SafeValue -> UnitValue SignalValue SafeValue
instance Unit Hertz SafeValue
instance Unit SamplePerSecond Integer
instance Unit Sample Integer
-- Not a unit in the sense of physics. One cycle represents start to finish of a sine wave in a timeless domain
instance Unit Cycle SafeValue
instance Unit Second SafeValue
instance Unit Amplitude SafeValue -- Not a unit in the sense of physics. One amplitude represents the ability to transform a SignalValue
-- Definitely not a unit in the sense of physics. We (explicitly) break unit laws by converting to other units.
instance Unit SignalValue SafeValue
instance Unit SignalSlope SafeValue
instance Progression Cycle SafeValue
instance Progression Second SafeValue
instance Progression Sample Integer
instance UnitRelationship Cycle Second Hertz SafeValue SafeValue SafeValue
-- sortof lame that I have to do the commutative manually, but I actually don't want it
-- automatically implied anyway. for instance, I see no reason (yet) to end up with
-- a sampling rate as a result, that should actually be constant
instance UnitRelationship Cycle Hertz Second SafeValue SafeValue SafeValue
instance UnitRelationship Sample Second SamplePerSecond Integer SafeValue Integer
instance UnitRelationship Sample SamplePerSecond Second Integer Integer SafeValue
instance UnitRelationship SignalValue Sample SignalSlope SafeValue Integer SafeValue
instance UnitRelationship SignalValue SignalSlope Sample SafeValue SafeValue Integer
-- This will make sure Amplitude inputs are used correctly.
instance UnitRelationship Amplitude SignalValue SignalValue SafeValue SafeValue SafeValue
get_frequency :: UnitValue Second SafeValue -> UnitValue Cycle SafeValue -> UnitValue Hertz SafeValue
get_frequency s c = c /: s
get_seconds :: UnitValue Hertz SafeValue -> UnitValue Cycle SafeValue -> UnitValue Second SafeValue
get_seconds h c = c /: h
add_5_seconds s = (s :: (UnitValue Second SafeValue)) +: _second 5