output 1 $ aws --region us -west -1 ec2 describe -availability -zones 2 AVAILABILITYZONES us -west -1 available us -west -1a 3 AVAILABILITYZONES us -west -1 available us -west -1c 4 5 $ aws --region us -west -2 ec2 describe -availability -zones 6 AVAILABILITYZONES us -west -2 available us -west -2a 7 AVAILABILITYZONES us -west -2 available us -west -2b 8 AVAILABILITYZONES us -west -2 available us -west -2c 9 10 $ aws --region us -east -1 ec2 describe -availability -zones 11 AVAILABILITYZONES us -east -1 available us -east -1a 12 AVAILABILITYZONES us -east -1 available us -east -1b 13 AVAILABILITYZONES us -east -1 available us -east -1c 14 AVAILABILITYZONES us -east -1 available us -east -1e 15

wild many times 1 # Written on some date a couple of years ago when 2 # you first migrated to AWS in your dev account. 3 availability_zones = { 4 us_west_1: [ "us -west -1a" "us -east -1c" ], 5 us_west_2: [ "us -west -2a" "us -west -2b" "us -west -2c" ], 6 # Missing the new AZ us -east -1e 7 us_east_1: [ "us -east -1a" "us -east -1b" "us -east -1c" ] 8 } 9 # Same idea for limits 10 limits = { ... } 11

conﬁg.yaml ﬁles’ over time yields stale assumptions that only get reviewed at time of error 2 Reactive (not proactive) does not take advantage of accounts new capabilities in a region 3 Not reusable across accounts each AWS account has diﬀerent available AZs per region with diﬀerent AZ mappings

rules/policies Rules deﬁned in terms of operating environment state; remove hard coding, improve maintainability and trustworthiness/business value of rules codebase. 2 Validate existing deployments validate infrastructure deployed meets cost, availability, capability, security policies 3 Validate deployments against policies pre-deployment prevent deploying cloud resources that violate security, cost, availability, capabiity policies and don’t pay AWS a dime for "bad" infrastructure 4 Manage infrastructure requirements Managing infrastructure/deployment requirements by encoding them as propositions translated to types and proved with deﬁnitions that typecheck

required almost everywhere 2 Human high churn/turnover, low quality of ops life; kills innovation 3 Technological FP and expressive type systems no longer just for academics and programmable infrastructure is everywhere now

a mechanism that constructs types from a structured source outside the programming language. Common traits of type providers include ingesting a schema-based dataset to construct types from metadata that is stable for the duration of the running program.

dependent types we can compute types and know that the computed types compile. This is not true for source/byte code generated type providers which may generate code that does not compile. 1 data CSVType : Type where 2 MkCSVType : (delim : Char) -- delim label not strictly necessary here 3 → (n : Nat) 4 → (hdr : Vect n String) 5 → CSVType 6 Listing 5: typecomputation.idr

type Prelude.Providers.Provider : (a : Type) → Type 3 Type providers must build one of these in an IO computation. 4 5 Constructors: 6 Provide : (x : a) → Provider a 7 Return a term to be spliced in 8 Args: x : a -- the term to be spliced (i.e. the proof) 9 Error : (msg : String) → Provider a 10 Report an error to the user and stop compilation 11 Args: msg : String -- the error message 12 Listing 6: 0. Review Provider a type deﬁnition - Basically a Either a String

() 3 main = 4 do let fn = "female_serial_killers.csv" 5 f <- readCSVFile t fn 6 case f of 7 Nothing ⇒ putStrLn "Could not open CSV file " ++ fn 8 Just rows ⇒ 9 do let birthYears = map getBirthYear rows 10 let names = map getName rows 11 putStrLn $ show birthYears 12 putStrLn $ show names 13 Listing 13: Main.idr - 6. Use the provided action

features* Propositions as types (Proofs as deﬁnitions) * too many implications/assumptions to put here but search for "Curry-Howard constructive logic" or "intuitionistic logic" for further reading

even or odd. where even is deﬁned as for some p in the naturals n = 2p and odd is deﬁned as for some p in the naturals n = 2p + 1. (∀n ∈ N, ∃p ∈ N : n = 2p or n = 2p + 1) 1 natsAreEvenOrOdd : (n : Nat) 2 → (p : Nat ** Either (Even n p) (Odd n p)) 3 Listing 14: Proposition in Idris types

2p where p = 0 ∈ N Assume n = 2p + 1 ∈ N then =⇒ n + 1 = 2p + 1 + 1 =⇒ n + 1 = 2p + 2 =⇒ n + 1 = 2(p + 1) =⇒ n + 1 = 2q where q = (p + 1) ∈ N Else we assume n = 2p ∈ N then =⇒ n + 1 = 2p + 1 =⇒ n + 1 = 2p + 1 where p ∈ N

Truth value, so we use the singleton type. This means only one value can be constructed for that type. Listing 15: truth.scala 1 type Truth = Unit 1 Truth : Type 2 Truth = () Listing 16: truth.idr

values of this type can be constructed). We call this the bottom type. Listing 17: falsity.scala 1 // Technically Null has one inhabitant in Scala , which 2 // is the value ‘null ‘. All types in Scala have ‘null ‘ 3 // as an inhabitant (fancy word for value ). 4 // Nothing is also a somewhat suitable type in Scala to 5 // specifically denote non -termination sense of "bottom ". 6 // Thank you @jpfuentes2 for suggestion of Nothing. 7 type Falsity = Null 1 Falsity : Type 2 Falsity = Void Listing 18: falsity.idr

then we can say, given a value of type a we can return a value of type b. Listing 19: implication.scala 1 type Implication[A, B] = (A => B) 1 Implication : (a: Type) → (b : Type) → Type 2 Implication a b = (a → b) 3 4 implicationExample : Bool → Nat 5 implicationExample False = Z 6 implicationExample True = S Z Listing 20: implication.idr

fancy word for logical NOT. Since Falsity can never be inhabited, then saying NOT a means given a value of type a then we must return the bottom type (NOT a means a is Falsity). Note: we cannot do Not (Not P) => P. Listing 21: negation.scala 1 type Negation[A] = A => Null 1 Negation : Type → Type 2 Negation = Not Listing 22: negation.idr

word for logical AND. Given a value of type a and a value of type b both are returned. We use the Pair type in the Idris Prelude to represent this case. Special purpose product types can also represent this bottom type. Listing 23: conjuction.scala 1 type Conjunction[A,B] = (A, B) 1 Conjunction : Type → Type → Type 2 Conjunction = Pair Listing 24: conjunction.idr

word for logical OR. Given a value of type a and a value of type b we return either the a or the b (exclusive OR). Listing 25: disjunction.scala 1 type Disjunction[A, B] = Either[A, B] 1 Disjunction : Type → Type → Type 2 Disjunction = Either Listing 26: disjunction.idr

logical propositions make sense when all put together. In programming we can ensure this by checking types/functions are total. A type being total is just a fancy way of saying that for all inhabitants (values) of any inputs to the function/type, we will always be able to terminate with an inhabitant of the return value in some ﬁnite time.

module/file code 2 %default total 3 4 -- not strictly necessary since above we specified 5 -- the default as total 6 total 7 parity : (n : Nat) → Parity n 8 9 -- When you can’t validate totality, eg. with IO/effectful 10 -- code that interacts with the outside world rather than axioms 11 -- or definitions then we might need to specify it is partial 12 -- (assuming you specified the default to total like above). 13 partial 14 main : IO () 15 main = someActionHere

mathematics/logic. We saw this in the all naturals are either even or odd example before. In programming we have recursion which is how we prove by induction in Idris. 1 -- FYI: 2 -- cong : (a = b) → f a = f b 3 4 bla : (n : Nat) → (m : Nat) → S (plus n m) = plus n (S m) 5 bla Z m = Refl 6 bla (S k) m = cong (bla k m) Listing 28: induction.idr

for "describe how many of something". The Universal Quantiﬁer is a fancy term for "for all x in X". 1 -- Proposition that says for all n in Naturals and all m in Naturals 2 -- we can construct a Vect of length (n+m) with Nat elements. 3 -- Anyone know anything parametricity? What is the likely form of 4 -- the proof of such a proposition that we can construct? :) 5 someType : (n : Nat) → (m : Nat) → Vect (n+m) Nat Listing 29: universal.idr

term for "there exists x in X such that P". : asz) -> 1 someType : (n : Nat) 2 → (p : Nat ** Either (Even n p) (Odd n p)) 3 4 -- (x : t ** a → Type) desugars to the following type: 5 -- data DPair : (a : Type) (P : a → Type) → Type where 6 -- MkDPair : (x : a) → (prf : P x) → DPair a P 7 8 -- So we could write: 9 -- someType : (n : Nat) 10 -- → DPair (p : Nat) (Either (Even n p) (Odd n p)) Listing 30: existential.idr

itself 2 Even : (n : Nat) → (p : Nat) → Type 3 Odd : (n : Nat) → (p : Nat) → Type 4 zeroIsEven : Even Z Z 5 succEven : Even n p → Odd (S n) p 6 succOdd : Odd n p → Even (S n) p 7 8 -- Proposition restated as a type 9 natsAreEvenOrOdd : (n : Nat) 10 → (p : Nat ** Either (Even n p) (Odd n p)) 11 -- Proof of the proposition when we fill the hole and ensure it’s total 12 natsAreEvenOrOdd Z = (0 ** Left (Even 0 0)) -- base case 13 natsAreEvenOrOdd (S n) = ?hole -- induction via recursion 14 Listing 31: Equivalent proposition and proof in Idris

region, we want to ensure our deployment of EC2 resources deﬁnes a cluster of a multiple oﬀ the number of availability zones for even distribution. 1 evenDistributionAcrossAZs : (account : AWSAccount) 2 → (region : Region) 3 → (x : Nat) 4 → Vect x AZ 5 → (n : Nat ** Cluster (mult x n) Service) Listing 32: striped.idr