+125
Haskell/solvingProblems.org
+125
Haskell/solvingProblems.org
···
1
+
* Reverse Polish Notation Calculator
2
+
3
+
[[https://en.wikipedia.org/wiki/Reverse_Polish_notation][Link for the wikipedia for the explanation]]
4
+
5
+
#+begin_src haskell
6
+
import Data.List
7
+
#+end_src
8
+
9
+
#+RESULTS:
10
+
11
+
#+begin_src haskell
12
+
:{
13
+
solveRPN :: String -> Float
14
+
solveRPN = head . foldl foldingFunction [] . words
15
+
where foldingFunction (x:y:ys) "*" = (x * y):ys
16
+
foldingFunction (x:y:ys) "+" = (x + y):ys
17
+
foldingFunction (x:y:ys) "-" = (y - x):ys
18
+
foldingFunction (x:y:ys) "/" = (y / x):ys
19
+
foldingFunction (x:y:ys) "^" = (y ** x):ys
20
+
foldingFunction (x:xs) "ln" = log x:xs
21
+
foldingFunction xs "sum" = [sum xs]
22
+
foldingFunction xs numberString = read numberString:xs
23
+
:}
24
+
25
+
solveRPN "10 10 10 10 sum 4 /"
26
+
#+end_src
27
+
28
+
#+RESULTS:
29
+
: Prelude Data.List> 10.0
30
+
31
+
* Heathrow to London
32
+
33
+
Your plane just landed in England and you rent a car.
34
+
You have a meeting really soon and you have to get fro Heathrow Airport to London as fast as you can (but safely!).
35
+
36
+
There are two main roads going from Heathrow to London and there's a number of regional roads crossing them.
37
+
It takes you a fixed amount of time to travel from one crossroads to another.
38
+
It's up to you to find the optimal path to take so that you get to London as fast as you can!
39
+
You start on the lest side and can either cross to the other main road or go forward.
40
+
41
+
Our job is to make a program that takes input that represents a road system and print out what the shortert path across it is.
42
+
Here's what the input would look like for this care:
43
+
44
+
#+begin_example
45
+
50
46
+
10
47
+
30
48
+
5
49
+
90
50
+
20
51
+
40
52
+
2
53
+
25
54
+
10
55
+
8
56
+
0
57
+
#+end_example
58
+
59
+
To mentally parse the input file, read it in threes and mentally split the road system into sections.
60
+
Each section is comprised of a road A, road B and a crossing road.
61
+
To have it neatly fit into threes, we say that there's a last crossing section that takes 0 minutes to drive over.
62
+
That's because we don't care where we arrive in London, as long as we're in London.
63
+
64
+
To get the best path we do this: first we see what the best path to the next crossroads on main road A is.
65
+
The two options are going directly forward or starting at the opposite road, going forward and then crossing over.
66
+
We remember the cost and the path. We use the same method to see what the best path to the next crossroads on main road B is and remember that.
67
+
Then, we see if the path to the next crossroads on A is cheaper if we go prom the previous A crossroads or if we to from the previous B crossroads and then cross over.
68
+
We remember the cheaper path and then we to the same for the crossroads opposite of it.
69
+
We do this for every section until we reach the end.
70
+
Once we've reachead the end, the cheapest of the two paths that we have is our optimal path!
71
+
72
+
So in essence, we keep one shortest path on the road A and one path on the B road and when we reach the end, the shorter of those two ir our path.
73
+
74
+
#+begin_src haskell
75
+
:{
76
+
data Section = Section { getA :: Int, getB :: Int, getC :: Int } deriving (Show)
77
+
type RoadSystem = [Section]
78
+
79
+
heathrowToLondon :: RoadSystem
80
+
heathrowToLondon = [Section 50 10 30, Section 5 90 20, Section 40 2 25, Section 10 8 0]
81
+
82
+
data Label = A | B | C deriving (Show)
83
+
type Path = [(Label, Int)]
84
+
85
+
roadStep :: (Path, Path) -> Section -> (Path, Path)
86
+
roadStep (pathA, pathB) (Section a b c) =
87
+
let priceA = sum $ map snd pathA
88
+
priceB = sum $ map snd pathB
89
+
forwardPriceToA = priceA + a
90
+
crossPriceToA = priceB + b + c
91
+
forwardPriceToB = priceB + b
92
+
crossPriceToB = priceA + a + c
93
+
newPathToA = if forwardPriceToA <= crossPriceToA
94
+
then (A,a):pathA
95
+
else (C,c):(B,b):pathB
96
+
newPathToB = if forwardPriceToB <= crossPriceToB
97
+
then (B,b):pathB
98
+
else (C,c):(A,a):pathA
99
+
100
+
in (newPathToA, newPathToB)
101
+
102
+
103
+
optimalPath :: RoadSystem -> Path
104
+
optimalPath roadSystem =
105
+
let (bestAPath, bestBPath) = foldl roadStep ([], []) roadSystem
106
+
in if sum (map snd bestAPath) <= sum (map snd bestBPath)
107
+
then reverse bestAPath
108
+
else reverse bestBPath
109
+
110
+
resolveProblem :: RoadSystem
111
+
resolveProblem roadSystem =
112
+
let path = optimalPath roadSystem
113
+
pathString = concat $ map (show . fst) path
114
+
pathPrice = sum $ map snd path
115
+
putStrLn $ "The best path to take is: " ++ pathString
116
+
putStrLn $ "The price is: " ++ pathPrice
117
+
:}
118
+
119
+
resolveProblem heathrowToLondon
120
+
#+end_src
121
+
122
+
#+RESULTS:
123
+
: Prelude Data.List>
124
+
: <interactive>:208:1-14: error:
125
+
: Variable not in scope: resolveProblem :: RoadSystem -> t