Skip to content

Commit 94a5195

Browse files
committed
Constructive Programming - Workshop One
1 parent af9cdb0 commit 94a5195

File tree

3 files changed

+352
-0
lines changed

3 files changed

+352
-0
lines changed

constructive-programming/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.html
2+
*.tex
3+
*.out
4+
*.aux
5+
*.log
6+
*.pdf

constructive-programming/common.org

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#+AUTHOR: Rodolfo Hansen
2+
#+KEYWORDS: ADT, Software, Types, CorrectByConstruction
3+
#+OPTIONS: toc:2
4+
#+OPTIONS: reveal_width:1600 reveal_height:1200
5+
#+REVEAL_HLEVEL: 2
6+
#+REVEAL_TRANS: slide
7+
#+REVEAL_THEME: moon
8+
#+REVEAL_HLEVEL: 1
9+
#+REVEAL_PLUGINS: (zoom,highlight,progress)
10+
#+REVEAL_MIN_SCALE: 0.8
11+
#+REVEAL_MAX_SCALE: 4.0
12+
#+REVEAL_MARGIN: 0
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
#+TITLE: A Hands-On Algebriac Approach to Software Construction
2+
#+INCLUDE: "./common.org"
3+
4+
* Introduction:
5+
6+
This workshop series is about bringing together logic (constructive logic),
7+
computation (scala), and composition (category theory) into the vocabulary and
8+
tool-set of us mortal programmers; so there will be a lot of inter-connected
9+
topics swimming around this workshop, so the more discussions we get going,
10+
the more connections we should be able to share between these subjects.
11+
12+
These three ideas come together very nicely in terms of constructing
13+
maintainable software that is verified to meet business rules by the language
14+
compiler.
15+
16+
On our first day, we will do some /'warm up'/ exercises to think of our data
17+
types, and functions as logical propositions, and explore some theorems from
18+
logic /(universal constructions from a categorical perspective)/ available
19+
for our re-use.
20+
21+
We will also introduce Functors as Quatifiers and link first order logic to
22+
type constructors and imagine whole system proof building.
23+
24+
Let's start calling this: *Constructive Programming*
25+
26+
* Correct by Construction
27+
** Referential Transparency:
28+
29+
You might correct me, and say we could, or have decided when something is an
30+
algebra or a calculus or a recipe; that we have ways to disambiguate or
31+
distinguish between synonyms, But
32+
33+
*** Unit as output?
34+
35+
#+BEGIN_SRC scala
36+
//What can you do here without breaking referencial transparency?
37+
def func[A](a: A): Unit
38+
39+
//Is this useful?/
40+
def alwaysTrue[A](a: A): Unit
41+
42+
//Is this different than alwaysTrue? can we guarantee subsequent
43+
//transformations (steps)?
44+
def println(s: String): Unit
45+
#+END_SRC
46+
47+
*** Values as output
48+
49+
#+BEGIN_SRC scala
50+
//Can I substitute the result with this expresion?
51+
def getTime(): DateTime
52+
53+
//Can I garauntee subsequent steps?
54+
def open(path: String): File
55+
56+
//What pitfalls can come up here?
57+
def logValue[A](a: A): A
58+
59+
//Why is this sub-optimal?
60+
def build(a: ExpensiveArtifact): ExpensiveArtifact
61+
#+END_SRC
62+
63+
*** Shared state
64+
65+
#+BEGIN_SRC scala
66+
//What could go wrong here?!
67+
var cnt = 0
68+
def countingMapper[A, B](l: List[A]: f: A => B): List[B]
69+
def reset(): Unit
70+
#+END_SRC
71+
72+
** Total Functions:
73+
*** Expanding the co-domain
74+
#+BEGIN_SRC scala
75+
//What could go wrong here?!
76+
//Will any string be convertible to an A?
77+
def decode[A](s: String): A
78+
79+
// Will we always find an A?
80+
def head[A](l: List[A]): A
81+
#+END_SRC
82+
83+
*** Contracting the domain
84+
#+BEGIN_SRC scala
85+
//What could go wrong here?!/
86+
//Is division possible for all b?
87+
def divide(a: Int, b: Int): Int
88+
89+
// Will we always need an A?
90+
def head[A](l: List[A]): A
91+
#+END_SRC
92+
93+
*** Exhaustive matching
94+
#+BEGIN_SRC scala
95+
//What could go wrong here?!
96+
//Can we garauntee subsequent transformations?
97+
98+
trait Shape
99+
100+
def center(shape: Shape): (Int, Int)
101+
#+END_SRC
102+
103+
** Termination:
104+
#+BEGIN_SRC scala
105+
//What could go wrong here?!
106+
def use[A](a: A): A = use(a)
107+
#+END_SRC
108+
109+
* Simple Logic Excercises (but not predicate logic) (prove)
110+
#+BEGIN_SRC scala
111+
type /\[A, B] = (A, B)
112+
type \/[A, B] = Either[A, B]
113+
// type =>[A, B] = A => B
114+
type <==>[A, B] = A => B /\ B => A
115+
// What could go wrong here?!
116+
type Not[A] = A => Nothing
117+
118+
// Corrolaries / Universal Constructions
119+
def and_1[A, B](n: A /\ B): A = ???
120+
def and_2[A, B](n: A /\ B): B = ???
121+
def or_1[A, B](a: A): A \/ B = ???
122+
def or_2[A, B](b: B): A \/ B = ???
123+
def mp[A, B](a: A, f: A => B): B = ???
124+
def exp[A, B, C](a: A, g: (A /\ B) => C): B => C = ???
125+
def bicond_1[A, B](f: A <==> B): A => B = ???
126+
def bicond_2[A, B](f: A <==> B): B => A = ???
127+
128+
def ex_falso_1[A](n: Nothing): A = ???
129+
def ex_falso_2[A](n: Nothing): Not[A] = ???
130+
def dist_law[A, B, C](h: A \/ (B \/ C)) = (A \/ B) \/ (A \/ C) = ???
131+
def shunting[A, B, C](n: A /\ B => C) = A => B => C = ???
132+
#+END_SRC
133+
134+
* Sync up Exercises
135+
Catching everyone up:
136+
137+
1. Come up with some domain objects in health and fitness.
138+
1.1. Let's think of some products and some sums.
139+
1.2. Let's think of some ands and ors.
140+
2. Come up with some functions that interact with this domain.
141+
2.1. Let's calculate the possible number of pure total functions that exist for those function types.
142+
2.2. Let's think of some propositions.
143+
3. Did we write any optics?
144+
3.1. Let's write an optics library.
145+
146+
* Quantifying (ways of leaving the zeroth order logic)
147+
Scala's syntax does not help clarify quantifiers. But that is fine, the 3rd
148+
encoding is one we will want to focus on.
149+
150+
** Existential
151+
#+BEGIN_SRC scala
152+
//What could go wrong here?!
153+
//Encoding 1
154+
type Exists[P[_]] = P[A] forSome {type A}
155+
156+
def exampleFor1 = ???
157+
158+
//Encoding 2
159+
trait ForSome { type A; def value: A }
160+
161+
def proofFor2[T](t: T): ForSome = new ForSome {
162+
type A = T
163+
val value = t
164+
}
165+
166+
def exampleFor2 = ???
167+
168+
//Encoding 3 (Bounded)
169+
trait Feature[P[_], A] {
170+
def exist: P[A]
171+
}
172+
173+
def proofFor3[P[_], A](t: P[A]): Feature[P, A] =
174+
new Feature[P] { def exist = t }
175+
176+
def exampleFor3 = ???
177+
#+END_SRC
178+
179+
** Universal
180+
#+BEGIN_SRC scala
181+
//What could go wrong here?!
182+
//Encoding 1/
183+
trait Forall[P[_]] { def apply[A]: P[A] }
184+
185+
def proofFor1[P[_]](t: P[A]): Forall[P] =
186+
new Forall { def apply = t }
187+
188+
def exampleFor1 = ???
189+
190+
//Encoding 3 (Bounded)
191+
trait Feature[P[_], Q[_]] {
192+
def apply(a: P[A]): Q[A]
193+
}
194+
195+
def proofFor3[P[_], Q[_]](t: P[A] => Q[A]): Feature[P, Q] =
196+
new Feature { def apply(p: P[A]) = t(p) }
197+
198+
def exampleFor3 = ???
199+
#+END_SRC
200+
201+
** Shapeless
202+
Anecdotally, Shapeless smooths the edges of scala around quantification;
203+
allowing for more fine grained implications:
204+
205+
#+BEGIN_SRC scala
206+
//What could go wrong here?!/
207+
//shapeless' poly/
208+
209+
object size extends Poly1 {
210+
211+
implicit def caseInt = at[Int](x => 1)
212+
213+
implicit def caseString = at[String](_.length)
214+
215+
implicit def caseTuple[T, U](implicit st : Case.Aux[T, Int],
216+
su : Case.Aux[U, Int]) =
217+
at[(T, U)](t => size(t._1)+size(t._2))
218+
219+
}
220+
#+END_SRC
221+
222+
** Optics
223+
224+
#+BEGIN_SRC scala
225+
//What could go wrong here?!/
226+
type Gender = Boolean
227+
type BirthDate = LocalDate
228+
229+
case class Person(name: String, birthDate: BirthDate, gender: Gender)
230+
case class Man(name: String, birthDate: BirthDate)
231+
232+
val personToMan: Person => Option[Man] = _ match {
233+
case Person(name, birthDate, True) => Some(Man(name, birthDate))
234+
case p => None
235+
236+
}
237+
238+
val manToPerson: Man => Person = m => Person(m.name, m.birthDate, True)
239+
240+
val getTime: IO[LocalDate] = ???
241+
242+
val personAge: Person => IO[Int] = p => getTime.map(p.birthDate.yearsBetween)
243+
244+
val manAge_1: Man => Option[IO[Int]] = ???
245+
val manAge_2: Man => IO[Int] = ???
246+
247+
case class Lens[S, A](get: S => A, set: A => S => S) {
248+
def modify(A => B): Lens[S, B] = ???
249+
250+
def compose[T](other: Lens[T, S]): Lens[T, A] = ???
251+
252+
def choice[T](other: Lens[T, A]): Lens[S \/ T, A] = ???
253+
254+
def split[T, B](other: Lens[T, B]): Lens[S /\ T, A /\ B] = ???
255+
256+
}
257+
#+END_SRC
258+
259+
** Functors
260+
261+
#+BEGIN_SRC scala
262+
//What could go wrong here?!/
263+
trait Functor[F[_]] {
264+
265+
def map[A, B](fa: F[A])(f: A => B): F[B] = ???
266+
267+
}
268+
#+END_SRC
269+
270+
** Twan van Laarhoven Lens
271+
#+BEGIN_SRC scala
272+
//What could go wrong here?!/
273+
case class Const[A, B](a: A) implicit def constFunctor[AA] = new
274+
Functor[Const[AA, ?]] {
275+
276+
def map[A, B](fa: Const[AA, A])(f: A => B): Const[AA, B] = ???
277+
278+
}
279+
280+
type TVL[S, A] = (Const[A, S], A => S) implicit def tvlFunctor[A] = new
281+
Functor[TVL[?, A]] {
282+
283+
def map[S, T](fa: TVL[S, A])(f: S => T): TVL[T, A] = ???
284+
285+
} trait Lens[S, A] {
286+
def apply[F[_]: Functor](A => F[A]): S => F[S]
287+
def get(s: S): A = ???
288+
def set(a: A, s: S): S = ???
289+
def modify(A => B): Lens[S, B] = ???
290+
def compose[T](other: Lens[T, S]): Lens[T, A] = ???
291+
def choice[T](other: Lens[T, A]): Lens[S \/ T, A] = ???
292+
def split[T, B](other: Lens[T, B]): Lens[S /\ T, A /\ B] = ???
293+
}
294+
#+END_SRC
295+
296+
* Extras
297+
** Exponent laws, Logic and Cats
298+
[[https://ncatlab.org/nlab/show/relation+between+type+theory+and+category+theory][https://ncatlab.org/nlab/show/relation+between+type+theory+and+category+theory]]
299+
[[https://www.infoq.com/presentations/category-theory-propositions-principle]]
300+
301+
#+BEGIN_SRC scala
302+
Arrow ~> a ^ c x b ^ c = (a x b) ^ c
303+
304+
ArrowChoice ~> c ^ a x c ^ b = c ^ (a + b)
305+
306+
FunctionK ~> b ^ (c x a) = b ^ a ^ c
307+
#+END_SRC
308+
309+
** Sudoku
310+
#+BEGIN_SRC scala
311+
// Let's write a sudoku solver/
312+
313+
type Digit = Int Refined Digit
314+
type Cell = Option[Digit]
315+
type Board = Array[Array[Cell]]
316+
def solver: Board => Array[Board] = ???
317+
#+END_SRC
318+
319+
[[https://www.cs.tufts.edu/~nr/cs257/archive/richard-bird/sudoku.pdf]]
320+
321+
** Bowling Kata
322+
323+
[[https://deque.blog/2017/07/01/idris-bowling-katahttps://deque.blog/2017/07/01/idris-bowling-kata][https://deque.blog/2017/07/01/idris-bowling-kata]]
324+
325+
** Color Theorem
326+
[[https://www.ams.org/notices/200811/tx081101382p.pdf]]
327+
* References
328+
- [[https://en.wikipedia.org/wiki/Predicate_functor_logic]]
329+
- [[https://en.wikipedia.org/wiki/Curry%27s_paradox]]
330+
- [[https://bartoszmilewski.com/2013/10/08/lenses-stores-and-yoneda/]]
331+
- [[https://bartoszmilewski.com/2015/07/13/from-lenses-to-yoneda-embedding/]]
332+
- [[https://github.com/SethTisue/lens-examples/blob/master/src/main/scala/VanLaarhovenLenses.scala]]
333+
- [[https://github.com/hablapps/LensAlgebra]]
334+
- [[https://github.com/hablapps/stateless]]

0 commit comments

Comments
 (0)