Skip to content

Commit bf444c5

Browse files
author
Oskar Lundström
committed
Dolde kod, skrev om dold kod, fixade lösningar och annan hyfsnings i Dim.Intro ValueLevel och VLtest
1 parent e9f5dee commit bf444c5

File tree

6 files changed

+120
-130
lines changed

6 files changed

+120
-130
lines changed

Physics/Instruktioner.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
# Pandoc
1515

16-
Komilera med ` pandoc FILNAMN.lhs -f markdown+lhs -t html -o FILNAMN.html -s --mathjax`.
16+
Komilera med `pandoc FILNAMN.lhs -f markdown+lhs -t html -o FILNAMN.html -s --mathjax`.
1717

1818
# Python
1919

Physics/src/Dimensions/Intro.lhs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The dimension of a quantity is often implicitly understood given its unit. If I
1616

1717
There are 7 *base dimensions*, each with a corresponding SI-unit.
1818

19-
![The 7 base dimensions](Base_dimensions.png)
19+
![](Base_dimensions.png "The 7 base dimensions")
2020

2121
- Length (metre)
2222
- Mass (kilogram)

Physics/src/Dimensions/Quantity.lhs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ TODO: What is the purpose (semantics, intended meaning or use) of Quantity'?
113113
< data Quantity' (d1 :: T.Dim) (d2 :: T.Dim) where
114114
< Quantity' :: Rational -> Rational -> Quantity' d1 d2
115115
116-
</div>
117-
</details>
116+
</div>
117+
</details>
118118
119119
A taste of types
120120
----------------

Physics/src/Dimensions/ValueLevel.lhs

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,6 @@
22
Value-level dimensions
33
======================
44

5-
From the introduction, two things became apparanent:
6-
7-
1. Given the unit of a quantity, its dimension is known implicitly.
8-
2. If we only work with SI-units, there is a one-to-one correspondence between dimensions and units.
9-
10-
We'll use these facts when implementing dimensions. More precisely, "length" and "metre" will be interchangable, and so on.
11-
12-
What you see below is the [Haskell module syntax](http://learnyouahaskell.com/modules#making-our-own-modules). Why do we show it to you? Because we don't want to hide any code from you if you follow along this tutorial.
13-
145
> module Dimensions.ValueLevel
156
> ( Dim(..)
167
> , mul
@@ -24,10 +15,17 @@ What you see below is the [Haskell module syntax](http://learnyouahaskell.com/mo
2415
> , luminosity
2516
> , one
2617
> ) where
27-
18+
>
2819
> import Prelude hiding (length, div)
2920

30-
A dimension can be seen as a product of the base dimensions, with an individual exponent on each base dimension. Since the 7 base dimensions are known in advance, we can design our data type using this fact.
21+
From the introduction, two things became apparanent:
22+
23+
1. Given the unit of a quantity, its dimension is known implicitly.
24+
2. If we only work with SI-units, there is a one-to-one correspondence between dimensions and units.
25+
26+
We'll use these facts when implementing dimensions. More precisely, "length" and "metre" will be interchangable, and so on.
27+
28+
A dimension can be seen as a product of the base dimensions, with an individual exponent on each base dimension. Because the 7 base dimensions are known in advance, we can design our data type using this fact.
3129

3230
> data Dim = Dim Integer -- Length
3331
> Integer -- Mass
@@ -64,8 +62,8 @@ Noticed how we used "m" (for metre) for implicitly refering to the dimension "le
6462
> area = Dim 2 0 0 0 0 0 0
6563
> charge = Dim 0 0 1 1 0 0 0
6664

67-
</div>
68-
</details>
65+
</div>
66+
</details>
6967

7068
Multiplication and division
7169
---------------------------
@@ -86,8 +84,8 @@ Dimensions can be multiplied and divided. Velocity is, as we just saw, a divisio
8684
> (Dim le1 ma1 ti1 cu1 te1 su1 lu1) `div` (Dim le2 ma2 ti2 cu2 te2 su2 lu2) =
8785
> Dim (le1-le2) (ma1-ma2) (ti1-ti2) (cu1-cu2) (te1-te2) (su1-su2) (lu1-lu2)
8886

89-
</div>
90-
</details>
87+
</div>
88+
</details>
9189

9290
It's now possible to construct dimensions in the following fashion.
9391

@@ -96,8 +94,6 @@ It's now possible to construct dimensions in the following fashion.
9694
> force = mass `mul` acceleration
9795
> momentum = force `mul` time
9896

99-
TODO: try to replace "since" by "because" (in many places) to avoid confusion with the meaning of "since" in the time-domain.
100-
10197
A dimension we so far haven't mentioned is the *scalar*, which shows up when working with, for example, coefficients of friction. It's dimensionless because it arises from division of two equal dimensions. The case of coefficients of friction looks like
10298

10399
\begin{align}
@@ -113,19 +109,21 @@ A dimension we so far haven't mentioned is the *scalar*, which shows up when wor
113109
> one = Dim 0 0 0 0 0 0 0
114110
> one' = force `div` force
115111

116-
</div>
117-
</details>
112+
</div>
113+
</details>
118114

119115
Pretty-printer
120116
--------------
121117

122-
![A not so pretty printer](Printer.png){.float-img-left}
118+
![](Printer.png "A not so pretty printer"){.float-img-left}
123119

124120
The purpose of value-level dimensions is to be able to print 'em nicely. The pretty printer should be function with the type
125121

126122
< showDim :: Dim -> String
127123

128-
meaning it shows a dimension as a string. How to actually implement this is not the interesting part in this tutorial, so you may with good conscience skip this implementation. However, if you're curios, you can still take a look at it.
124+
meaning it shows a dimension as a string. But how to actually implement this is not the interesting part of this tutorial. Hence we skip it.
125+
126+
\ignore{
129127

130128
> showDim :: Dim -> String
131129
> showDim (Dim le ma ti cu te su lu)
@@ -156,11 +154,15 @@ meaning it shows a dimension as a string. How to actually implement this is not
156154
> len :: (Integral n) => [a] -> n
157155
> len [] = 0
158156
> len (a:as) = 1 + len as
159-
>
157+
158+
}
159+
160+
We use `showDim` to make `Dim` an instance of `Show`
161+
160162
> instance Show Dim where
161163
> show = showDim
162164

163-
Now dimensions are printed quite pretty in GHCi.
165+
Now dimensions are printed quite prettily in GHCi
164166

165167
< ghci> momentum
166168
< kg*m/s

Physics/src/Dimensions/ValueLevel/Test.lhs

Lines changed: 59 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
Testing of value-level dimensions
33
=================================
44

5-
![Both you, me and dimensions need to obey the laws](Laws.png){.float-img-left}
6-
7-
For operations on dimensions, there are a number of laws which should hold. We will here test that the value-level dimensions obey them. One way is to use `QuickCheck`, which produces lots o' random test cases.
8-
95
> module Dimensions.ValueLevel.Test
106
> ( runTests
117
> ) where
12-
8+
>
139
> import Prelude hiding (length, div)
1410
> import Test.QuickCheck
1511
> import Data.List
16-
12+
>
1713
> import Dimensions.ValueLevel
1814

15+
![](Laws.png "Both you, me and dimensions need to obey the laws"){.float-img-left}
16+
17+
For operations on dimensions, there are a number of laws which should hold. We will here test that the value-level dimensions obey them. One way is to use `QuickCheck`, which produces lots o' random test cases.
18+
1919
Generating arbitrary dimensions
2020
-------------------------------
2121

@@ -34,7 +34,7 @@ An arbitrary example of an `Arbitrary` instance (get it?) could look like
3434
< instance Arbitrary IntPair where
3535
< arbitrary = genIntPair
3636

37-
**Exercise.** Now try to implement an `Arbitrary` instance of `Dim`.
37+
**Exercise** Now try to implement an `Arbitrary` instance of `Dim`.
3838

3939
<details>
4040
<summary>**Solution**</summary>
@@ -56,8 +56,8 @@ Here's one way to do it.
5656
> instance Arbitrary Dim where
5757
> arbitrary = genDim
5858

59-
</div>
60-
</details>
59+
</div>
60+
</details>
6161

6262
Properties for operations on dimensions
6363
---------------------------------------
@@ -71,7 +71,10 @@ The laws to test are
7171
- `one` is a unit for multiplication
7272
- Multiplication and division cancel each other out
7373
- Dividing by `one` does nothing
74-
- Dividing by a division brings up the lowest denominator [TODO: strange wording?? Perhaps use a formula instead. (and perhaps use `recip` to simplify?)]
74+
- Dividing by a division brings up the lowest denominator
75+
\begin{align}
76+
\frac{x}{\frac{x}{y}} = y
77+
\end{align}
7578
- Multiplication by $x$ is the same as dividing by the inverse of $x$.
7679

7780
The implementation of the first law looks like
@@ -97,10 +100,6 @@ Here's what the rest could look like.
97100
> prop_mulOneUnit :: Dim -> Bool
98101
> prop_mulOneUnit d = d == one `mul` d
99102

100-
> -- Property: dividing twice results in no change
101-
> prop_divTwice :: Dim -> Dim -> Bool
102-
> prop_divTwice d1 d2 = d1 `div` (d1 `div` d2) == d2
103-
104103
> -- Property: multiplication and division cancel each other out
105104
> prop_mulDivCancel :: Dim -> Dim -> Bool
106105
> prop_mulDivCancel d1 d2 = (d1 `mul` d2) `div` d1 == d2
@@ -109,104 +108,59 @@ Here's what the rest could look like.
109108
> prop_divOne :: Dim -> Bool
110109
> prop_divOne d = d `div` one == d
111110

111+
> -- Property: dividing by a division brings up the lowest denominator
112+
> prop_divTwice :: Dim -> Dim -> Bool
113+
> prop_divTwice d1 d2 = d1 `div` (d1 `div` d2) == d2
114+
112115
> -- Property: multiplication same as division by inverse
113116
> prop_mulDivInv :: Dim -> Dim -> Bool
114117
> prop_mulDivInv d1 d2 = d1 `mul` d2 ==
115118
> d1 `div` (one `div` d2)
116119

117-
</div>
118-
</details>
119-
120-
Testing the pretty-printer
121-
--------------------------
122-
123-
TODO: It is good that you test it, but I suggest you keep that out of the learning material [perhaps a link to "extra reading"].
124-
125-
We rely pretty heavily on the pretty-printer. Let's test it too! We won't get too ambitious in our testing of it. It'll be enough to check that if a dimension has a nonzero
126-
127-
TODO: Do something about the problem of m and mol.
128-
129-
-- Property: pretty-printed has correct of a dimension
130-
prop_correctDim :: Integer -> Dim -> Bool
131-
prop_correctDim i d = prop_correctDim' (i `mod` 7) d (show d)
132-
133-
prop_correctDim' :: Integer -> Dim -> String -> Bool
134-
prop_correctDim' 0 (Dim le ma ti cu te su lu) str =
135-
prop_correctDim'' le "m" str
136-
prop_correctDim' 1 (Dim le ma ti cu te su lu) str =
137-
prop_correctDim'' ma "kg" str
138-
prop_correctDim' 2 (Dim le ma ti cu te su lu) str =
139-
prop_correctDim'' ti "s" str
140-
prop_correctDim' 3 (Dim le ma ti cu te su lu) str =
141-
prop_correctDim'' cu "A" str
142-
prop_correctDim' 4 (Dim le ma ti cu te su lu) str =
143-
prop_correctDim'' te "K" str
144-
prop_correctDim' 5 (Dim le ma ti cu te su lu) str =
145-
prop_correctDim'' su "mol" str
146-
prop_correctDim' 6 (Dim le ma ti cu te su lu) str =
147-
prop_correctDim'' lu "cd" str
148-
149-
prop_correctDim'' :: Integer -> String -> String -> Bool
150-
prop_correctDim'' exp unit str
151-
| exp == 0 = occursNever unit num &&
152-
occursNever unit den
153-
| exp == 1 = occursOnce unit num &&
154-
occursNever unit' num &&
155-
occursNever unit den
156-
| exp == -1 = occursOnce unit den &&
157-
occursNever unit num
158-
| exp > 1 = occursOnce unit' num &&
159-
occursNever unit den
160-
| exp < -1 = occursOnce unit' den &&
161-
occursNever unit num
162-
| otherwise = True
163-
where
164-
num = takeWhile(/='/') str
165-
den = dropWhile(/='/') str
166-
unit' = unit ++ "^" ++ (show (abs exp))
167-
168-
-- TODO: Check that it only occurs once.
169-
170-
-- kg^2 (eller dylikt) ska finns exakt en gång i rätt nivå
171-
-- och inte finns alls i fel nivå.
172-
173-
-- Exatcly once. Not more or less
174-
occursOnce :: (Eq a) => [a] -> [a] -> Bool
175-
occursOnce a = (==1) . numOccurs a
176-
177-
occursNever :: (Eq a) => [a] -> [a] -> Bool
178-
occursNever a = (==0) . numOccurs a
179-
180-
-- How many times the first list occurs in the second one
181-
numOccurs :: (Eq a) => [a] -> [a] -> Int
182-
numOccurs subList list = len $ filter (==subList) sg
183-
where
184-
sg = subGroups (len subList) list
185-
186-
-- Groups the list into lists of the specified length
187-
subGroups :: Int -> [a] -> [[a]]
188-
subGroups n _
189-
| n < 1 = error "Groups must be at least 1 big"
190-
subGroups _ [] = []
191-
subGroups n list@(_:rest)
192-
| n > len list = []
193-
| otherwise = (take n list):(subGroups n rest)
194-
195-
-- Length of a list
196-
len :: [a] -> Int
197-
len [] = 0
198-
len (x:xs) = 1 + len xs
199-
200-
Integrating tests with Stack
201-
----------------------------
202-
203-
This project uses `Stack`. One part of `Stack` is continous testing, and for it to work on the tests we developed here, the following functions is needed.
120+
</div>
121+
</details>
122+
123+
We should also test the pretty-printer. But just like how that function itself is implemented isn't interesting, neither is the code testing it. We therefore leave it out.
124+
125+
From this module, we export a function `runTests`. That function runs all the tests implemented here and is used with Stack.
126+
127+
\ignore{
128+
129+
> prop_correctDim :: Integer -> Dim -> Bool
130+
> prop_correctDim i d = prop_correctDim' (i `mod` 7) d (show d)
131+
>
132+
> prop_correctDim' :: Integer -> Dim -> String -> Bool
133+
> prop_correctDim' 0 (Dim le ma ti cu te su lu) str =
134+
> prop_correctDim'' le "m" str
135+
> prop_correctDim' 1 (Dim le ma ti cu te su lu) str =
136+
> prop_correctDim'' ma "kg" str
137+
> prop_correctDim' 2 (Dim le ma ti cu te su lu) str =
138+
> prop_correctDim'' ti "s" str
139+
> prop_correctDim' 3 (Dim le ma ti cu te su lu) str =
140+
> prop_correctDim'' cu "A" str
141+
> prop_correctDim' 4 (Dim le ma ti cu te su lu) str =
142+
> prop_correctDim'' te "K" str
143+
> prop_correctDim' 5 (Dim le ma ti cu te su lu) str =
144+
> prop_correctDim'' su "mol" str
145+
> prop_correctDim' 6 (Dim le ma ti cu te su lu) str =
146+
> prop_correctDim'' lu "cd" str
147+
>
148+
> prop_correctDim'' :: Integer -> String -> String -> Bool
149+
> prop_correctDim'' exp unit str
150+
> | exp == 0 = not $ isInfixOf unit str
151+
> | exp == 1 = isInfixOf unit num
152+
> | exp == -1 = isInfixOf unit den
153+
> | exp > 1 = isInfixOf (unit ++ "^" ++ show exp) num
154+
> | exp < -1 = isInfixOf (unit ++ "^" ++ show (abs exp)) den
155+
> where
156+
> num = takeWhile(/='/') str
157+
> den = dropWhile(/='/') str
204158

205159
> runTests :: IO ()
206160
> runTests = do
207161
> putStrLn "Dimensions value-level: Multiplication commutative"
208162
> quickCheck prop_mulCommutative
209-
> putStrLn "Dimensions value-level: ;ultiplication associative"
163+
> putStrLn "Dimensions value-level: Multiplication associative"
210164
> quickCheck prop_mulAssociative
211165
> putStrLn "Dimensions value-level: `one` is unit for multiplication"
212166
> quickCheck prop_mulOneUnit
@@ -218,3 +172,6 @@ This project uses `Stack`. One part of `Stack` is continous testing, and for it
218172
> quickCheck prop_divOne
219173
> putStrLn "Dimensions value-level: Multiplication by x is the same as dividing by the inverse of x"
220174
> quickCheck prop_mulDivInv
175+
176+
}
177+

0 commit comments

Comments
 (0)