-
Notifications
You must be signed in to change notification settings - Fork 52
Expand file tree
/
Copy pathAlgebra.hs
More file actions
200 lines (150 loc) · 6.51 KB
/
Copy pathAlgebra.hs
File metadata and controls
200 lines (150 loc) · 6.51 KB
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
module DSLsofMath.Algebra where
import qualified Data.Ratio
import qualified Prelude
import Prelude (Double, Rational, Int, Integer, Bool(..), otherwise,
Foldable(foldr), (.), const, (==), (<), error)
import Data.Complex
-------------------------------
-- Classes
infixl 6 -
infixl 6 +
infixl 7 *
infixl 7 /
class Additive a where
zero :: a
(+) :: a -> a -> a
sum :: (Foldable t, Additive a) => t a -> a
sum = foldr (+) zero
times :: Additive a => Integer -> a -> a
times n0 = if n0 < 0 then error "Algebra.Classes.times: negative number of times"
else go n0
where go 0 _ = zero
go 1 x = x
go n x = if r == 0 then twoy else x + twoy
where (m,r) = n `Prelude.divMod` 2
y = go m x
twoy = y+y
(-) :: AddGroup a => a -> a -> a
x - y = x + negate y
class Additive a => AddGroup a where
negate :: a -> a
mult :: AddGroup a => Integer -> a -> a
mult n x = if n < 0 then negate (times (negate n) x) else times n x
class Multiplicative a where
one :: a
(*) :: a -> a -> a
two :: (Additive a, Multiplicative a) => a
two = one+one
(^+) :: Multiplicative a => a -> Int -> a
x0 ^+ n0 = if n0 < 0 then error "Algebra.Classes.^: negative exponent"
else go n0 x0
where go 0 _ = one
go 1 x = x
go n x = if r == 0 then y2 else x * y2
where (m,r) = n `Prelude.divMod` 2
y = go m x
y2 = y * y
type Ring a = (AddGroup a, Multiplicative a)
fromInteger :: Ring a => Integer -> a
fromInteger n = mult n one
fromIntegral :: (Prelude.Integral a, Ring b) => a -> b
fromIntegral = fromInteger . Prelude.toInteger
class Multiplicative a => MulGroup a where
{-# MINIMAL (recip | (/)) #-}
recip :: a -> a
recip x = one / x
(/) :: a -> a -> a
x / y = x * recip y
(^) :: MulGroup a => a -> Int -> a
a ^ b | b < 0 = recip (a ^+ (negate b))
| otherwise = (a ^+ b)
type Field a = (Ring a, MulGroup a)
fromRational :: Field a => Data.Ratio.Ratio Integer -> a
fromRational x = fromInteger (Data.Ratio.numerator x) / fromInteger (Data.Ratio.denominator x)
class Field a => Algebraic a where
sqrt :: a -> a
-- normally it should be "Algebraic" instead of "Field" but we're lazy like that.
-- (Also Transcendental is a terrible name; taken from the "numeric prelude".)
class Field a => Transcendental a where
pi :: a
exp :: a -> a
sin :: a -> a
cos :: a -> a
cosh, sinh :: Transcendental a => a -> a
cosh x = (exp x + exp (negate x))/two
sinh x = (exp x - exp (negate x))/two
---------------------------------
-- Instances
instance Additive Int where (+) = (Prelude.+); zero = 0
instance Additive Integer where (+) = (Prelude.+); zero = 0
instance Additive Rational where (+) = (Prelude.+); zero = 0
instance Additive Double where (+) = (Prelude.+); zero = 0
instance AddGroup Int where negate = Prelude.negate
instance AddGroup Integer where negate = Prelude.negate
instance AddGroup Rational where negate = Prelude.negate
instance AddGroup Double where negate = Prelude.negate
instance Multiplicative Int where (*) = (Prelude.*); one = 1
instance Multiplicative Integer where (*) = (Prelude.*); one = 1
instance Multiplicative Rational where (*) = (Prelude.*); one = 1
instance Multiplicative Double where (*) = (Prelude.*); one = 1
instance MulGroup Rational where (/) = (Prelude./); recip = Prelude.recip
instance MulGroup Double where (/) = (Prelude./); recip = Prelude.recip
lift0 :: a -> (x->a)
lift1 :: (a->b) -> (x->a) -> (x->b)
lift2 :: (a->b->c) -> (x->a) -> (x->b) -> (x->c)
lift0 = const
lift1 = (.)
lift2 op2 f g = \x -> op2 (f x) (g x)
instance Additive a => Additive (x -> a) where (+) = lift2 (+); zero = lift0 zero
instance Multiplicative a => Multiplicative (x -> a) where (*) = lift2 (*); one = lift0 one
instance AddGroup a => AddGroup (x -> a) where negate = lift1 negate
instance MulGroup a => MulGroup (x -> a) where recip = lift1 recip
instance Algebraic a => Algebraic (x -> a) where sqrt = lift1 sqrt
instance Transcendental a => Transcendental (x -> a) where
pi = lift0 pi; sin = lift1 sin; cos = lift1 cos; exp = lift1 exp
instance Algebraic Double where sqrt = Prelude.sqrt
instance Transcendental Double where
pi = Prelude.pi; sin = Prelude.sin; cos = Prelude.cos; exp = Prelude.exp
instance Additive a => Additive (Complex a) where (+) = addC; zero = zeroC
instance Ring a => Multiplicative (Complex a) where (*) = mulC; one = oneC
instance AddGroup a => AddGroup (Complex a) where negate = negateC
instance Field a => MulGroup (Complex a) where recip = recipC
addC :: Additive a => Complex a -> Complex a -> Complex a
addC (x :+ y) (x' :+ y') = (x + x') :+ (y+y')
negateC :: AddGroup a => Complex a -> Complex a
negateC (a :+ b) = negate a :+ negate b
mulC :: Ring a => Complex a -> Complex a -> Complex a
mulC (a :+ b) (a' :+ b') = (a * a' - b * b') :+ (a * b' + b * a')
toC :: Additive a => a -> Complex a
toC x = x :+ zero
zeroC :: Additive a => Complex a
zeroC = toC zero
oneC :: (Additive a, Multiplicative a) => Complex a
oneC = toC one
recipC (a :+ b) = (a / m) :+ (negate b / m)
where m = a*a + b*b
instance (Algebraic a, Prelude.RealFloat a) => Algebraic (Complex a) where
sqrt = Prelude.sqrt
instance (Transcendental a) => Transcendental (Complex a) where
pi = piC; exp = expC; sin = sinC; cos = cosC
piC :: Transcendental a => Complex a
piC = toC pi
expC, sinC, cosC, sinhC, coshC :: Transcendental a => Complex a -> Complex a
expC (x:+y) = expx * cos y :+ expx * sin y where expx = exp x
sinC (x:+y) = sin x * cosh y :+ cos x * sinh y
cosC (x:+y) = cos x * cosh y :+ negate (sin x * sinh y)
sinhC (x:+y) = cos y * sinh x :+ sin y * cosh x
coshC (x:+y) = cos y * cosh x :+ sin y * sinh x
---------------------------------
-- For RebindableSyntax
ifThenElse :: Bool -> p -> p -> p
ifThenElse c a b = if c then a else b
-------------------------------
-- Typesetting aliases.
neg :: AddGroup a => a -> a
neg = negate -- |neg| is used to typeset unary minus as a shorter dash, closer to its argument
frac :: MulGroup a => a -> a -> a
frac = (/) -- |frac| is used to typeset a fraction (more compactly than |x / y|)