├── .gitignore ├── modeling_data_in_haskell ├── Makefile ├── hero.hs ├── modeling_data.md └── worksheets.tex ├── monad_transformers ├── Makefile └── transformers.md ├── moot ├── Makefile ├── book_of_monads.png ├── moot.md └── moot.pdf ├── newtype_type_safety ├── Makefile └── typesafety.md └── rank_n_types_talk ├── .gitignore ├── Makefile ├── examples.hs ├── exist.hs ├── muchnicer.png ├── painitself.png ├── rankn.md ├── rankn.pdf ├── ranks.hs └── tuple.hs /.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | .DS_Store 3 | *.aux 4 | *.log 5 | *.pdf 6 | -------------------------------------------------------------------------------- /modeling_data_in_haskell/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | pandoc -t dzslides -s modeling_data.md -o modeling_data.html 3 | 4 | # xelatex -halt-on-error -shell-escape -job-name=worksheets worksheets.tex 5 | -------------------------------------------------------------------------------- /modeling_data_in_haskell/hero.hs: -------------------------------------------------------------------------------- 1 | module RPG where 2 | 3 | data Hero = 4 | Hero { 5 | class :: String 6 | , race :: String 7 | , statusEffects :: [String] 8 | , inventory :: Map String Int 9 | } deriving Show 10 | -------------------------------------------------------------------------------- /modeling_data_in_haskell/modeling_data.md: -------------------------------------------------------------------------------- 1 | % Modeling data in Haskell 2 | % Chris Allen 3 | % April 30, 2015 4 | 5 | 6 | # Haskell has a nice type system 7 | 8 | - Lets try to make proper use of it 9 | 10 | - So no more of this: 11 | 12 | ```haskell 13 | whoKnows :: String -> Map String String -> IO () 14 | ``` 15 | 16 | You can't reason about it. 17 | 18 | 19 | # Haskell datatype syntax 20 | 21 | Nullary constructor: 22 | 23 | ```haskell 24 | data Trivial = Trivial 25 | -- [1] [2] 26 | ``` 27 | 28 | 1. Type constructor 29 | 30 | 2. Data constructor - takes no arguments, thus "nullary" 31 | 32 | 33 | # Constructors? 34 | 35 | We use type constructors to refer to types by name in type signatures. 36 | 37 | ```haskell 38 | f :: String -> String -> String 39 | f = ...doesn't matta... 40 | ``` 41 | 42 | Here we refer to the type `String` three times in our type signature, denoted syntactically by the double colon `::` 43 | 44 | We use data constructors to create values. There's some special syntax for built-in types like String, List, tuples, but in most cases you'll use a data constructor explicitly introduced by the datatype. 45 | 46 | 47 | # So which is which? 48 | 49 | ```haskell 50 | data TrivialTypeConstructor 51 | = TrivialDataConstructor 52 | ``` 53 | 54 | Rule of thumb: before the `=` is the type constructor, after the `=` are the data constructors. 55 | 56 | If there's a single data constructor, it'll often have the same name as the type constructor because types and values are strictly separated in Haskell. 57 | 58 | 59 | # How do we use our datatype with a single nullary data constructor? 60 | 61 | ```haskell 62 | theProofIs :: Trivial 63 | theProofIs = Trivial 64 | 65 | trivialityBegets :: Trivial -> Trivial 66 | trivialityBegets Trivial = Trivial 67 | 68 | -- alternately 69 | trivialityBegets _ = Trivial 70 | 71 | -- or 72 | trivialityBegets x = Trivial 73 | ``` 74 | 75 | 76 | # Haskell datatype syntax 77 | 78 | Unary constructor (takes one argument): 79 | 80 | ```haskell 81 | data Identity a = Identity a 82 | -- [1] [2] 83 | ``` 84 | 85 | 1. Type constructor, takes one argument. 86 | 87 | 2. Data constructor, takes one argument. Thus, "unary". Unary/nullary refers to the data constructor. You'll see examples with multiple data constructors of mixed arity later. 88 | 89 | 90 | # How do we use Identity? 91 | 92 | ```haskell 93 | unpack :: Identity a -> a 94 | unpack (Identity a) = a 95 | 96 | embed :: a -> Identity a 97 | embed a = Identity a 98 | 99 | imap :: (a -> b) -> Identity a -> Identity b 100 | imap f (Identity a) = Identity (f a) 101 | ``` 102 | 103 | Identity doesn't do much, so if this seems pointless, you're not missing anything. 104 | 105 | 106 | # Type constructor has to agree with data constructor 107 | 108 | Why can't we have: 109 | 110 | ```haskell 111 | data Identity = Identity a 112 | ``` 113 | 114 | Because you'll get the error: `Not in scope: type variable ‘a’` 115 | 116 | Without the argument existing for the data *and* the type constructor, we have no means of expressing what we think `Identity` contains. There ways to "hide" the type variables in data constructors from the type constructors but that's for another day. 117 | 118 | 119 | # Product 120 | 121 | What happens if you add another argument to a unary data constructor? Products! 122 | 123 | ```haskell 124 | data Person = Person String Int 125 | ``` 126 | 127 | Product here can also be read to mean, "record" or "struct", but be careful with assumptions about representation. Here `Person` is a product of a `String` and an `Int`. 128 | 129 | 130 | # Person with record syntax 131 | 132 | ```haskell 133 | data Person = Person { name = String 134 | , age = Int } 135 | ``` 136 | 137 | `Person` defined using record syntax for the fields. 138 | 139 | Using the field accessors: 140 | 141 | ```haskell 142 | getName :: Person -> String 143 | getName p = name p 144 | 145 | -- eta reduce 146 | 147 | getName = name 148 | 149 | -- redundant 150 | ``` 151 | 152 | # Tuples 153 | 154 | Tuples are our "anonymous product", so called because we don't name anything. We could rewrite our `Person` type as: 155 | 156 | ```haskell 157 | type Person = (String, Int) 158 | ``` 159 | 160 | The `type` keyword only creates type constructors, that is, aliases to other types with their own data constructors. You could refer to this value `("blah", 3)` has having type `Person`. 161 | 162 | 163 | # Nesting tuples 164 | 165 | You can also nest tuples. Given the product of `String` *and* `Int` *and* `Integer` *and* another `String` you could write that as: 166 | 167 | ```haskell 168 | (String, (Int, (Integer, String))) 169 | ``` 170 | 171 | This is what makes the 2-tuple an anonymous universal product, that we can nest them. 172 | 173 | 174 | # Exercises 175 | 176 | Rewrite the following type into a nested two tuple: 177 | 178 | ```haskell 179 | data Car = Car { 180 | make :: CarMake 181 | , model :: CarModel 182 | , year :: CarYear 183 | } 184 | ``` 185 | 186 | turns into: 187 | 188 | ```haskell 189 | type Car = ??? 190 | ``` 191 | 192 | 193 | # Exercises 194 | 195 | Given the functions: 196 | 197 | ```haskell 198 | fst :: (a, b) -> a 199 | snd :: (a, b) -> b 200 | ``` 201 | 202 | Add the accessors back for your nested tuple type. 203 | 204 | ```haskell 205 | make :: Car -> CarMake 206 | make = undefined 207 | 208 | model :: Car -> CarModel 209 | model = undefined 210 | 211 | year :: Car -> CarYear 212 | year = undefined 213 | ``` 214 | 215 | 216 | # Sum type 217 | 218 | The Bool datatype is defined as follows: 219 | 220 | ```haskell 221 | data Bool = False | True 222 | ``` 223 | 224 | What we've done here is made it so two different data constructors are values of type `Bool`. Where `product` ~ *and*, `sum` ~ *or*. 225 | 226 | 227 | # We have an anonymous sum type too 228 | 229 | ```haskell 230 | data Either a b = Left a | Right b 231 | ``` 232 | 233 | 234 | # Gettin' silly 235 | 236 | We could atomise `Bool` like so: 237 | 238 | ```haskell 239 | data False' = False' deriving Show 240 | data True' = True' deriving Show 241 | 242 | type Bool' = Either False' True' 243 | ``` 244 | 245 | 246 | # Bonus 247 | 248 | It'll even type-check that you're not messing the order up: 249 | 250 | ``` 251 | Prelude> Right False' :: Bool' 252 | 253 | :57:7: 254 | Couldn't match expected type ‘True'’ 255 | with actual type ‘False'’ 256 | In the first argument of ‘Right’, 257 | namely ‘False'’ 258 | In the expression: Right False' :: Bool' 259 | Prelude> Right True' :: Bool' 260 | Right True' 261 | ``` 262 | 263 | 264 | # Making the "algebra" in algebraic data types do work 265 | 266 | - There's an actual set of operations here. 267 | 268 | ```haskell 269 | data Bool = False | True 270 | ``` 271 | 272 | - False = 1 273 | - True = 1 274 | - | = + 275 | - Either also = + 276 | 277 | ```haskell 278 | data Bool = False + True 279 | 280 | data Bool = 1 + 1 281 | Bool = 2 inhabitants 282 | ``` 283 | 284 | 285 | # Making the "algebra" in algebraic data types do work 286 | 287 | ```haskell 288 | type Bool' = Either False' True' 289 | 290 | Either = + 291 | 292 | data False' = False' 293 | 294 | False' = 1 295 | True' = 1 296 | 297 | type Bool' = Either 1 1 298 | = 1 + 1 299 | -- same as ordinary Bool 300 | -- we can say they are equivalent 301 | ``` 302 | 303 | # Making the "algebra" in algebraic data types do work 304 | 305 | Knowing how big your domain is important for knowing how comprehensible it is, as well as knowing how it relates 306 | 307 | (,) = * 308 | 309 | ```haskell 310 | type DoesntMatter = (Bool, Bool) 311 | 312 | type DoesntMatter = Bool * Bool 313 | 314 | type DoesntMatter = 2 * 2 315 | 316 | type DoesntMatter = 4 inhabitants 317 | ``` 318 | 319 | 320 | # Exercises 321 | 322 | How many inhabitants does each type have? 323 | 324 | ```haskell 325 | -- Word8 = 0-255 326 | 327 | import Data.Word 328 | 329 | type A = Either Word8 Bool 330 | 331 | type B = (Word8, Bool) 332 | 333 | type C = Either (Bool, Word8) (Word8, Bool) 334 | ``` 335 | 336 | 337 | # Don't do this 338 | 339 | ```haskell 340 | data CarType = Null | 341 | Car { carid :: Int 342 | , position :: Float 343 | , speed :: Float, 344 | , carLength :: Float 345 | , state :: [Float] 346 | } deriving (Show,Eq) 347 | ``` 348 | 349 | 350 | # Why? 351 | 352 | Because it's redundant, obnoxious, and it introduces partial functions. Don't mix record syntax and sum types! 353 | 354 | Partial what? Partial functions are functions that have inputs for which they don't have answers. 355 | 356 | ``` 357 | data Example = Null 358 | | Example { 359 | blah :: Int 360 | } deriving Show 361 | Prelude> blah $ Example 10 362 | 10 363 | Prelude> blah $ Null 364 | *** Exception: No match in record selector blah 365 | ``` 366 | 367 | 368 | # Pls no. 369 | 370 | `Maybe` exists, use it! 371 | 372 | ```haskell 373 | data Maybe a = Nothing | Just a 374 | ``` 375 | 376 | If you have a function that might not be able to return a sensible `CarType`, return `Maybe CarType`! 377 | 378 | 379 | # Cleaning up our datatypes 380 | 381 | This isn't great. 382 | 383 | ```haskell 384 | data Hero = 385 | Hero { 386 | class :: String 387 | , race :: String 388 | , statusEffects :: [String] 389 | , inventory :: Map String Int 390 | } deriving Show 391 | ``` 392 | 393 | You're not getting a lot of mileage out of the type system when you do this. 394 | 395 | 396 | # Exercise 397 | 398 | Tell me how to fix the `Hero` datatype. 399 | -------------------------------------------------------------------------------- /modeling_data_in_haskell/worksheets.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \begin{document} 4 | 5 | \section{Worksheet \#1} 6 | 7 | Rewrite the following types into tuple syntax 8 | 9 | \begin{enumerate} 10 | 11 | \item 12 | 13 | \item 14 | 15 | \end{enumerate} 16 | 17 | \newpage 18 | 19 | \section{Worksheet \#2} 20 | 21 | \end{document} 22 | -------------------------------------------------------------------------------- /monad_transformers/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | pandoc -t dzslides -s transformers.md -o transformers.html 3 | -------------------------------------------------------------------------------- /monad_transformers/transformers.md: -------------------------------------------------------------------------------- 1 | % Monad transformers 2 | % Chris Allen 3 | % October 30, 2014 4 | 5 | 6 | # Functors 7 | 8 | - We're going to talk about functors before moving on to monads and monad transformers 9 | 10 | - You always have a functor and an applicative functor whenever you have a monad 11 | 12 | 13 | # What's a functor? 14 | 15 | ```haskell 16 | class Functor f where 17 | fmap :: (a -> b) -> f a -> f b 18 | ``` 19 | 20 | Plus the laws: 21 | 22 | ```haskell 23 | fmap id == id 24 | fmap (f . g) == fmap f . fmap g 25 | ``` 26 | 27 | 28 | # Why do laws matter? 29 | 30 | This law is usually called "identity". This is also about structure preservation. 31 | 32 | ```haskell 33 | fmap id == id 34 | ``` 35 | 36 | And this one is about compositionality. Without this, we don't have code we can compose safely. 37 | 38 | ```haskell 39 | fmap (f . g) == fmap f . fmap g 40 | ``` 41 | 42 | Without these laws, we can assume very little about what fmap does. 43 | 44 | 45 | # What does this mean for us? 46 | 47 | Identity 48 | 49 | ```haskell 50 | Prelude> let myList = [1, 2, 3] 51 | Prelude> id myList 52 | [1,2,3] 53 | Prelude> fmap id myList 54 | [1,2,3] 55 | ``` 56 | 57 | Composing 58 | 59 | ```haskell 60 | Prelude> fmap (*2) . fmap (+1) $ myList 61 | [4,6,8] 62 | Prelude> fmap ((*2) . (+1)) myList 63 | [4,6,8] 64 | ``` 65 | 66 | 67 | # What's fmap, really? 68 | 69 | Lets shift the parentheses a bit. Since the type constructor for functions `->` is right associative, the following re-parenthesization is correct. 70 | 71 | From: 72 | 73 | ```haskell 74 | (a -> b) -> f a -> f b 75 | ``` 76 | 77 | To: 78 | 79 | ```haskell 80 | (a -> b) -> (f a -> f b) 81 | ``` 82 | 83 | There are a few ways to describe this. One is that we're lifting `(a -> b)` into the environment `f`. Another is that we're mapping `(a -> b)` over `f`. Mostly this does not matter as long as you don't confuse the map with the territory. 84 | 85 | 86 | # List functor 87 | 88 | List 89 | 90 | ```haskell 91 | (a -> b) -> [a] -> [b] 92 | ``` 93 | 94 | ```haskell 95 | instance Functor [] where 96 | fmap f = foldr ((:) . f) [] 97 | ``` 98 | 99 | We've seen this already 100 | 101 | ```haskell 102 | Prelude> fmap (+1) [1, 2, 3] 103 | [2,3,4] 104 | Prelude> fmap (+1) [] 105 | [] 106 | ``` 107 | 108 | 109 | # Maybe functor 110 | 111 | Maybe 112 | 113 | ```haskell 114 | (a -> b) -> Maybe a -> Maybe b 115 | ``` 116 | 117 | ```haskell 118 | instance Functor Maybe where 119 | fmap f (Just x) = Just (f x) 120 | fmap _ Nothing = Nothing 121 | ``` 122 | 123 | ```haskell 124 | Prelude> fmap (+1) (Just 1) 125 | Just 2 126 | Prelude> fmap (+1) Nothing 127 | Nothing 128 | ``` 129 | 130 | 131 | # Kinds and types 132 | 133 | Kinds are types "one level up". We use them to describe the structure of type constructors. 134 | 135 | `*` is the default kind in Haskell and is used for all reference types (pointer to value or thunk). 136 | 137 | Int, Float, Char are all kind `*`. 138 | 139 | Lists, `[]`, are kind `* -> *` because they need a type before they can become real values. Once that type argument is applied, then it's a real type. 140 | 141 | 142 | # A mechanical demonstration of kinds 143 | 144 | We can ask Haskell to infer the kind of a type and tell us what it is in the REPL using `:kind`, oft abbreviated to `:k`. 145 | 146 | ```haskell 147 | Prelude> data Trivial0 = Trivial 148 | Prelude> :k Trivial0 149 | Trivial0 :: * 150 | 151 | Prelude> data Trivial1 a = Trivial 152 | Prelude> :k Trivial1 153 | Trivial1 :: * -> * 154 | ``` 155 | 156 | 157 | # A mechanical demonstration of kinds 158 | 159 | The terms, in this case a nullary constructor named "Trivial", don't matter for the purposes of this demonstration. 160 | 161 | ```haskell 162 | Prelude> data Trivial2 a b = Trivial 163 | Prelude> :k Trivial2 164 | Trivial2 :: * -> * -> * 165 | 166 | Prelude> data Trivial3 a b c = Trivial 167 | Prelude> :k Trivial3 168 | Trivial3 :: * -> * -> * -> * 169 | ``` 170 | 171 | 172 | # Kinds of day to day types 173 | 174 | ```haskell 175 | data [] a = [] | a : [a] 176 | -- with slightly different syntax 177 | data List a = Nil | Cons a (List a) 178 | 179 | data Maybe a = Nothing | Just a 180 | 181 | data Either a b = Left a | Right b 182 | ``` 183 | 184 | ```haskell 185 | Prelude> :kind [] 186 | [] :: * -> * 187 | Prelude> :kind Maybe 188 | Maybe :: * -> * 189 | Prelude> :kind Either 190 | Either :: * -> * -> * 191 | ``` 192 | 193 | 194 | # Functor and its kind 195 | 196 | One thing to note about the definition of functor is that it applies the type `f` to an argument `a` in the typeclass. 197 | 198 | ```haskell 199 | class Functor f where 200 | fmap :: (a -> b) -> f a -> f b 201 | ``` 202 | 203 | Since we have kind inference in Haskell (unlike say, Scala), Haskell is able to infer that `f` needs to be kind `* -> *` based on the fact that it gets applied to a single type argument `a`. 204 | 205 | 206 | # Functor and its kind 207 | 208 | To prove my point, let me demonstrate something that won't work. 209 | 210 | ```haskell 211 | module Blah where 212 | 213 | instance Functor Either where 214 | fmap = undefined 215 | ``` 216 | 217 | 218 | # Functor and its kind 219 | 220 | ``` 221 | Prelude> :l bad_code.hs 222 | Expecting one more argument to ‘Either’ 223 | The first argument of ‘Functor’ should have 224 | kind ‘* -> *’, 225 | but ‘Either’ has kind ‘* -> * -> *’ 226 | In the instance declaration for ‘Functor Either’ 227 | ``` 228 | 229 | (slightly edited to accommodate slide limitations) 230 | 231 | 232 | # Functor and its kind 233 | 234 | It doesn't matter that I stubbed out the implementation of `fmap` with `undefined` (useful trick btw), Either *cannot* implement Functor. But the kind is `* -> * -> *`. 235 | 236 | If Either is a type constructor that behaves like a function at the type level, what can we do with functions to get from `* -> * -> *` to `* -> *` ? 237 | 238 | 239 | # Fixing Either so we can get a Functor 240 | 241 | We *apply* it! Talking about a `Functor` for `Either` doesn't make any sense, but it does for `(Either a)`! 242 | 243 | 244 | # Fixing Either so we can get a Functor 245 | 246 | This changes our code to the following. 247 | 248 | ```haskell 249 | instance Functor (Either a) where 250 | fmap = undefined 251 | ``` 252 | 253 | Now it'll type-check. 254 | 255 | 256 | # Type variable scope 257 | 258 | ```haskell 259 | data Either a b = Left a | Right b 260 | ``` 261 | 262 | Ordinarily the `Functor` for `Either` maps over the contents of the `Right` data constructor. What happens 263 | if we write a typeclass that maps over the `Left`? 264 | 265 | 266 | # Either that maps over the Left 267 | 268 | ```haskell 269 | {-# LANGUAGE NoImplicitPrelude #-} 270 | 271 | module Blah where 272 | 273 | class Functor f where 274 | fmap :: (a -> b) -> f a -> f b 275 | 276 | data Either a b = Left a | Right b 277 | 278 | instance Functor (Either a) where 279 | fmap f (Left a) = Left (f a) 280 | fmap _ (Right b) = Right b 281 | ``` 282 | 283 | 284 | # Either that maps over the Left 285 | 286 | If you attempt the previous slide's code, you'll get the following type error (heavily abridged): 287 | 288 | ``` 289 | Couldn't match expected type ‘a’ with 290 | actual type ‘b’ 291 | ``` 292 | 293 | What does this mean? It means it expected `a` based on our terms but the types based on definition mean it needs to be `b`. 294 | 295 | 296 | # Why did it expect b? 297 | 298 | ```haskell 299 | data Either a b = Left a | Right b 300 | 301 | class Functor f where 302 | fmap :: (a -> b) -> f a -> f b 303 | 304 | instance Functor (Either a) where 305 | 306 | Either a == f 307 | 308 | a in f a == b in Either a b 309 | ``` 310 | 311 | 312 | # How to make a left-biased Either work 313 | 314 | ```haskell 315 | {-# LANGUAGE NoImplicitPrelude #-} 316 | 317 | module Blah where 318 | 319 | class Functor f where 320 | fmap :: (a -> b) -> f a -> f b 321 | 322 | data Either b a = Left a | Right b 323 | 324 | instance Functor (Either a) where 325 | fmap f (Left a) = Left (f a) 326 | fmap _ (Right b) = Right b 327 | ``` 328 | 329 | # Function functor 330 | 331 | `a -> b` is kind `* -> * -> *` because it has two type variables `a` and `b`. The first type variable is the argument type. 332 | 333 | Thus, a `Functor` instance for `a -> b` must be changing the result type, rather than the argument type because that'll be the unbound type variable when `(->)` is partially applied. This gives us the following Functor instance: 334 | 335 | ```haskell 336 | instance Functor ((->) a) where 337 | fmap = (.) 338 | ``` 339 | 340 | It's just function composition. 341 | 342 | 343 | # Weaker and stronger algebras 344 | 345 | - Functor is weaker than Applicative, Applicative is weaker than Monad. 346 | 347 | - Weakness of an algebra for Haskell means there are more types that have a valid instance. 348 | 349 | - But a weaker algebra means fewer derived operations...fewer things you can do with it. 350 | 351 | 352 | # Monad 353 | 354 | Typeclass definition 355 | 356 | ```haskell 357 | class Monad f where 358 | bind :: (a -> f b) -> f a -> f b 359 | ``` 360 | 361 | Not a semicolon. 362 | 363 | # Examples of monads 364 | 365 | List monad 366 | 367 | ```haskell 368 | -- since m here is [] 369 | bind :: (a -> [b]) -> [a] -> [b] 370 | ``` 371 | 372 | Maybe monad 373 | 374 | ```haskell 375 | -- since m is Maybe 376 | (a -> Maybe b) -> Maybe a -> Maybe b 377 | ``` 378 | 379 | # Examples of monads 380 | 381 | List monad 382 | 383 | ```haskell 384 | instance Monad [] where 385 | bind f xs = foldr ((++) . f) [] xs 386 | ``` 387 | 388 | Maybe monad 389 | 390 | ```haskell 391 | -- maybe :: b -> (a -> b) -> Maybe a -> b 392 | 393 | instance Monad Maybe where 394 | bind f a = maybe Nothing f a 395 | ``` 396 | 397 | # Examples of monads 398 | 399 | Reader (function) 400 | 401 | ```haskell 402 | -- applying the argument type again 403 | instance Monad ((->) t) where 404 | bind f g = \x -> f (g x) x 405 | ``` 406 | 407 | # Nesting data types 408 | 409 | What if I glue two functors, [] and Maybe together? 410 | 411 | ```haskell 412 | value :: [Maybe a] 413 | ``` 414 | 415 | and I want to map a function f :: a -> b 416 | 417 | ```haskell 418 | result :: [Maybe b] 419 | result f = fmap (fmap f) value 420 | ``` 421 | 422 | # Mapping on a (f of g) 423 | 424 | You can do this for any two functors: 425 | 426 | ```haskell 427 | value :: f (g a) 428 | ``` 429 | 430 | to map a function f :: a -> b 431 | 432 | ```haskell 433 | result :: f (g b) 434 | result f = fmap (fmap f) value 435 | ``` 436 | 437 | # Compose 438 | 439 | If f and g are functors, then (f of g) is a functor: 440 | 441 | ```haskell 442 | 443 | data Compose f g x = Compose (f (g x)) 444 | 445 | instance (Functor f, Functor g) => 446 | Functor (Compose f g) where 447 | fmap f (Compose z) = Compose (fmap (fmap f) z) 448 | ``` 449 | 450 | # Compose 451 | 452 | The composition of two arbitrary functors makes a new functor. Put briefly, *functors compose*. 453 | 454 | # Two monads 455 | 456 | if I glue two monads, [] and Maybe together: 457 | 458 | ```haskell 459 | value :: [Maybe a] 460 | ``` 461 | 462 | and I want to bind a function f :: a -> [Maybe b]: 463 | 464 | ```haskell 465 | 466 | -- return :: a -> m a 467 | result :: [Maybe b] 468 | result f = bind (maybe (return Nothing) f) value 469 | -- ^^ turns Maybe b into [Maybe b] 470 | ``` 471 | 472 | # Two monads 473 | 474 | We called bind on a list 475 | 476 | ```haskell 477 | result f = bind (maybe (return Nothing) f) value 478 | ^ ^ 479 | ``` 480 | 481 | but we destructured the Maybe using Maybe-specific calls 482 | 483 | # Can we compose monads? 484 | 485 | If f and g are monads, then is (f of g) a monad? 486 | 487 | Can we generalize? 488 | 489 | ```haskell 490 | instance (Monad f, Monad g) => 491 | Monad (Compose f g) where 492 | bind = error "???" 493 | ``` 494 | 495 | # Can we compose monads? 496 | 497 | You *can* compose monads, but the result is not guaranteed to be a monad. When you compose functors and applicatives, you are guaranteed to get a functor and an applicative respectively. 498 | 499 | But if you wanted to try to write a `Monad` instance for Compose you'd find it impossible to do so because the two Monad instances are polymorphic. 500 | 501 | You'd want this type: 502 | 503 | ```haskell 504 | :: (Monad m, Monad n) => m (n s) 505 | -> (s -> m (n t)) 506 | -> m (n t) 507 | ``` 508 |
509 | (this is impossible, give it a whack if you want) 510 | 511 | # If we know one monad 512 | 513 | We *can* bind on (f on Maybe) for any monad f. 514 | 515 | ```haskell 516 | result :: Monad f => 517 | (a -> f (Maybe b)) 518 | -> f (Maybe a) 519 | -> f (Maybe b) 520 | result = bind (maybe (return Nothing) f) value 521 | ``` 522 | 523 | # The Maybe monad transformer 524 | 525 | ```haskell 526 | data MaybeT f a = MaybeT { 527 | maybeT :: f (Maybe a) 528 | } 529 | 530 | instance Monad f => Monad (MaybeT f) where 531 | bind f (MaybeT x) = 532 | MaybeT (bind 533 | (maybe (return Nothing) 534 | (maybeT . f)) x 535 | ) 536 | ``` 537 | 538 | # The Maybe monad transformer 539 | 540 | Provides the construction of the monad for (f of Maybe) for an arbitrary 541 | monad f. Its behavior combines the individual monads of Maybe then f, in that order. 542 | 543 | This transformer exists because the composition of monads without specific knowledge of at least one of them doesn't give rise to a monad *in general*. 544 | 545 | # Example using List and Maybe 546 | 547 | ```haskell 548 | m1 :: MaybeT [] Integer 549 | m1 = MaybeT [Just 1, Just 2, Just 30] 550 | 551 | f1 :: Integer -> MaybeT [] Integer 552 | f1 n = 553 | MaybeT 554 | [ 555 | Just n 556 | , if n < 10 then Just (n * 50) else Nothing 557 | ] 558 | ``` 559 | 560 | ```haskell 561 | > maybeT (bind f1 m1) 562 | [Just 1, Just 50, Just 2, 563 | Just 100, Just 30, Nothing] 564 | ``` 565 | 566 | # Using Reader and Maybe 567 | 568 | ```haskell 569 | m2 :: MaybeT ((->) Integer) String 570 | m2 = MaybeT (\x -> 571 | if even x 572 | then Just (show (x * 10)) 573 | else Nothing 574 | 575 | f2 :: String -> MaybeT ((->) Integer) String 576 | f2 s = MaybeT (\n -> 577 | if n < 100 578 | then Just (show n ++ s) 579 | else Nothing) 580 | ``` 581 | 582 | ```haskell 583 | > map (maybeT (bind f2 m2)) [3, 4, 700] 584 | [Nothing, Just "440", Nothing] 585 | ``` 586 | 587 | # Other monad transformers 588 | 589 | ```haskell 590 | MaybeT f a = f (Maybe a) 591 | EitherT f a b = f (Either a b) 592 | ReaderT f a b = a -> f b 593 | StateT f s a = s -> f (s, a) 594 | ``` 595 | 596 | Each exists because the composition of monads are not guaranteed to give you a new monad. 597 | 598 | # Functor transformers don't even real 599 | 600 | Functor compose so what's the point? 601 | 602 | - Comonad transformers exist 603 | 604 | - Applicative transformers do not exist 605 | 606 | # Identity 607 | 608 | ```haskell 609 | newtype Identity a = Identity { runIdentity :: a } 610 | deriving (Eq, Ord) 611 | 612 | instance Functor Identity where 613 | fmap f m = Identity (f (runIdentity m)) 614 | 615 | instance Monad Identity where 616 | return a = Identity a 617 | m >>= k = k (runIdentity m) 618 | ``` 619 | 620 | # Identity Monad gets you back to the non-transformer version 621 | 622 | ```haskell 623 | MaybeT Identity a = Identity (Maybe a) 624 | EitherT Identity a b = Identity (Either a b) 625 | ReaderT Identity a b = a -> Identity b 626 | StateT Identity s a = s -> Identity (s, a) 627 | ``` 628 | -------------------------------------------------------------------------------- /moot/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | pandoc -t beamer -s moot.md -o moot.pdf 3 | -------------------------------------------------------------------------------- /moot/book_of_monads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitemyapp/presentations/297b62546c72101d8a95f7933525041f2121cdf0/moot/book_of_monads.png -------------------------------------------------------------------------------- /moot/moot.md: -------------------------------------------------------------------------------- 1 | % Moot 2 | % Chris Allen 3 | % June 5, 2018 4 | 5 | 6 | # LambdaConf has a pretty good process 7 | 8 | - Let's make it better! 9 | 10 | - CFP through editing, review, and scheduling 11 | 12 | - Tested process, serious formalization of a fair blinded process 13 | 14 | - The organizers have to juggle of a lot of variables 15 | 16 | 17 | # The LambdaConf organizers are wonderful, hard-working people 18 | 19 | - but they're still human 20 | 21 | - I'd like to incrementally automate their workflow and make their lives easier 22 | 23 | 24 | # Not just about LambdaConf 25 | 26 | - Lots of conferences have CFP and review processes they've invested in heavily 27 | 28 | - It's very manual, with some conference organizers writing homebrew scripts and using a menagerie of applications and services that don't interoperate. 29 | 30 | - Let's make this software available to others and help them automate what they're doing 31 | 32 | 33 | # Moot will be open source 34 | 35 | - License not yet decided, but the software will be open source and publicly available 36 | 37 | - Backend in Haskell 38 | 39 | 40 | # I need help, but I can offer help too 41 | 42 | - Need help from backend devs, frontend devs, designer 43 | 44 | - UX is important too! 45 | 46 | - Finished Haskell Book recently, looking to dive into an application? 47 | 48 | - I will tutor people that need help. Not just in the same capacity either! 49 | 50 | 51 | # Contact me if you're interested! 52 | 53 | - cma@bitemyapp.com 54 | 55 | - github.com/lorepub/moot 56 | -------------------------------------------------------------------------------- /moot/moot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitemyapp/presentations/297b62546c72101d8a95f7933525041f2121cdf0/moot/moot.pdf -------------------------------------------------------------------------------- /newtype_type_safety/Makefile: -------------------------------------------------------------------------------- 1 | # pandoc -t dzslides -s typesafety.md -o typesafety.html 2 | all: 3 | pandoc -t beamer -s typesafety.md -o typesafety.pdf 4 | -------------------------------------------------------------------------------- /newtype_type_safety/typesafety.md: -------------------------------------------------------------------------------- 1 | % Writing code that can't go wrong in Haskell 2 | % Chris Allen 3 | % June 19, 2014 4 | 5 | # newtype 6 | 7 | - newtype was prominently mentioned in the talk title 8 | 9 | - I’m not going to start by talking about newtype because I’ve noticed other prominent sources of errors in Haskell code as well. 10 | 11 | - Sorry. 12 | 13 | # Prelude is dangerous 14 | 15 | - The following functions should be relegated to a Prelude.Unsafe holding area: 16 | 17 | - length, head, tail, foldl1, fromJust, maximum, minimum, reverse, foldl, foldl’ - there might be others I’ve forgotten as well. 18 | 19 | # Prelude is dangerous 20 | 21 | - Prelude doesn’t encode uncertainty in the API where it’s possible to do so for partial functions 22 | 23 | - `head :: [a] -> a` — is a damn lie, surpassed in damnation only by statistics and politicians 24 | 25 | - Should be — `head :: [a] -> Maybe a` 26 | 27 | # Prelude is dangerous 28 | 29 | - What made head dangerous was the empty list case. There’s another problematic case - codata. 30 | 31 | - Coinductive lists are things like: [1..] 32 | 33 | - Coinduction guarantees productivity but not termination 34 | 35 | # Prelude is dangerous 36 | 37 | - length cannot and should not exist for a type that has the capability to be coinductive. 38 | 39 | - Nuts. 40 | 41 | - `length [1..]` -> bottom — this is gross. We’re betraying new people by leaving stuff like this in Prelude. 42 | 43 | # Crafting with negative space 44 | 45 | - Part of the value in learning Haskell is learning to craft with negative space 46 | 47 | - Most dyn-langs give you nothing *but* positive space to work with, but you have to no ability to *eliminate* possibilities. 48 | 49 | - This forces imprecision and implicitness in your APIs. This is unacceptable in 2014. 50 | 51 | # Crafting with negative space 52 | 53 | - The problem is that Prelude [a] conflates inductive and coinductive use-cases. Sometimes this is convenient, but unwise as a universal data structure. Is so for historical/simplicity reasons. 54 | 55 | - Use Vector or Sequence 56 | 57 | - and don’t use head dammit 58 | 59 | # Domain and codomain 60 | 61 | - String is a ridiculous type to have in your signatures 62 | 63 | - Probably lying. Is your function meant for *ALL POSSIBLE* Strings in the universe? 64 | 65 | - String being [Char] under the hood, this also conflates induction & conduction and making this the default text-y type is icky. 66 | 67 | # Domain and codomain 68 | 69 | - Int has a domain of 18446744073709551615 values. 70 | 71 | - Are you sure that’s what your API means when it says “Int”? Seeing String and Int in types is an API smell 72 | 73 | - Do you mean a hardware Int, size implicit to the machine int? 74 | 75 | # newtype to the rescue! 76 | 77 | - ```haskell 78 | data Webserver = Webserver String 79 | ``` 80 | 81 | - Nuke the String from orbit. You don’t mean all possible strings! 82 | 83 | - ```haskell 84 | newtype Host = Host String 85 | data Webserver = Webserver Host 86 | ``` 87 | 88 | - A modest improvement, but not compelling. 89 | Could still construct: 90 | Webserver (Host “GOBBLEBLUH”) 91 | 92 | # newtype to the rescue! 93 | 94 | - ```haskell 95 | newtype Host = Host String 96 | data Webserver = Webserver Host 97 | ``` 98 | 99 | - The problem is that our data isn’t being validated. 100 | 101 | - ```haskell 102 | -- hide the Host constructor 103 | newtype Host = Host String 104 | data Webserver = Webserver Host 105 | mkHost :: String -> Maybe Host 106 | mkHost hstr = -- …validation code… 107 | ``` 108 | 109 | # newtype to the rescue! 110 | 111 | - ```haskell 112 | newtype Host = Host String 113 | data Webserver = Webserver Host 114 | mkHost :: String -> Maybe Host 115 | ``` 116 | 117 | - But how do we use this? Webserver doesn’t expect Maybe Host. 118 | 119 | - Control.Applicative! Or if you have just one argument, Functor. 120 | 121 | # newtype to the rescue! 122 | 123 | - ```haskell 124 | newtype Host = Host String 125 | newtype Port = Port Int 126 | data Webserver = Webserver Host Port 127 | mkHost :: String -> Maybe Host 128 | mkPort :: Int -> Maybe Port 129 | ``` 130 | 131 | - ```haskell 132 | server :: Maybe Webserver 133 | server = Webserver 134 | <$> mkHost “google.com” 135 | <*> mkPort 80 136 | ``` 137 | 138 | - Thanks to Applicative, we don’t need to break out intermediate but independent uncertainty WRT Maybe values. Now we’re being explicit about uncertainty for possibly bad inputs. 139 | 140 | # But why is newtype important? 141 | 142 | - newtype drops all the baggage associated with a type, but getting to use its representation for free. It’s erased at compile-time. This means it’s effectively free WRT performance. 143 | 144 | - Not exporting a value constructor on a newtype or data type also gives you data hiding that doesn’t get violated nearly as often as in other languages (Scala, Java, Ruby, Python) 145 | 146 | - This also means you have no real excuse for not using it. 147 | 148 | # But why is newtype important? 149 | 150 | - Baggage dropped includes typeclass instances 151 | 152 | - This is how we maintain canonicity with typeclasses with types that share a representation 153 | 154 | - As a different language community would put it, we don’t *complect* the object with its representation 155 | 156 | # Record syntax is also dangerous 157 | 158 | - Uh, with sums of products that is. It’s okay otherwise. 159 | 160 | - ```haskell 161 | -- assume appropriate deriving 162 | data Blah = Woot | Alt { access :: Int } 163 | Prelude> :t access 164 | access :: Blah -> Int 165 | ``` 166 | 167 | - but what if it’s Woot instead of Alt? 168 | 169 | # Record syntax is sorta dangerous 170 | 171 | - ```haskell 172 | Prelude> blah Woot 173 | *** Exception: No match in record 174 | selector blah 175 | ``` 176 | 177 | - Well that’s not okay 178 | 179 | # Record syntax is dangerous if you’re being silly 180 | 181 | - You have two solutions to this sum-of-products & record syntax problem. 182 | 183 | - 1: Don’t use record syntax 184 | 185 | - 2: Split the record type out 186 | 187 | # Record syntax isn’t so bad 188 | 189 | ```haskell 190 | newtype AltProxy = AltProxy { access :: Int } 191 | data Blah = Woot | Alt AltProxy 192 | Prelude> :t access 193 | access :: AltProxy -> Int 194 | 195 | Prelude> blah Woot 196 | -- this is now a type error 197 | -- as Go^H^H SPJ intended. 198 | ``` 199 | 200 | # Record syntax isn’t so bad 201 | 202 | ```haskell 203 | newtype AltProxy = AltProxy { access :: Int } 204 | ``` 205 | 206 | ^^ doesn’t have to be a newtype and can’t be if there’s more than one field anyway 207 | 208 | Remember newtypes are just a cost-free way to create single value constructor data types. 209 | 210 | # Food for thought 211 | 212 | - Consider how splitting out more granular types can allow you to circumscribe value inhabitants of types in a way reminiscent of what dependently typed languages will allow. 213 | 214 | - If audience is curious and time allows, I can bring up an example demonstrating the (trivial) idea. 215 | 216 | -------------------------------------------------------------------------------- /rank_n_types_talk/.gitignore: -------------------------------------------------------------------------------- 1 | *.pdf 2 | -------------------------------------------------------------------------------- /rank_n_types_talk/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | pandoc -t beamer -s rankn.md -o rankn.pdf 3 | -------------------------------------------------------------------------------- /rank_n_types_talk/examples.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RankNTypes #-} 2 | 3 | module Examples where 4 | 5 | -- might remind you of an existential 6 | b :: (forall a. Show a => a -> String) -> (String, String) 7 | b f = (f 1, f 'v') 8 | -------------------------------------------------------------------------------- /rank_n_types_talk/exist.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE StandaloneDeriving #-} 2 | 3 | module Exist where 4 | 5 | newtype S = 6 | S { t :: forall a . Show a => a } 7 | 8 | deriving instance Show S 9 | -------------------------------------------------------------------------------- /rank_n_types_talk/muchnicer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitemyapp/presentations/297b62546c72101d8a95f7933525041f2121cdf0/rank_n_types_talk/muchnicer.png -------------------------------------------------------------------------------- /rank_n_types_talk/painitself.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitemyapp/presentations/297b62546c72101d8a95f7933525041f2121cdf0/rank_n_types_talk/painitself.png -------------------------------------------------------------------------------- /rank_n_types_talk/rankn.md: -------------------------------------------------------------------------------- 1 | % Rank-N Types Are Freakin' Sweet 2 | % Chris Allen 3 | % May 28, 2016 4 | 5 | # Rank N Types 6 | 7 | - Are awesome 8 | 9 | - Require understanding polymorphism in Haskell a bit first 10 | 11 | - So this talk doesn't really start at Rank-N types. 12 | 13 | # Polymorphism 14 | 15 | ```haskell 16 | id :: a -> a 17 | (+1) :: Num a => a -> a 18 | (+1) :: Int -> Int 19 | ``` 20 | 21 | 26 | 27 | # Universal quantification 28 | 29 | The type of identity can be read as, 30 | 31 | ```haskell 32 | id :: forall a . a -> a 33 | ``` 34 | 35 | For **all** _a_, _a_ to _a_ 36 | 37 | # Binders for type variables 38 | 39 | It turns out, our binders for types behave a lot like lambdas. 40 | 41 | ```haskell 42 | forall x . x 43 | \x -> x 44 | ``` 45 | 46 | This is how we bind variables to concrete types, characterize polymorphism. 47 | 48 | # Rank-1 49 | 50 | This is what Haskell type signatures all default to. 51 | 52 | Prenex-form is "outermost left-most". 53 | 54 | # Prenex form 55 | 56 | Means that when Haskell fills in the "forall" for you, this: 57 | 58 | ```haskell 59 | a -> b -> a 60 | ``` 61 | 62 | Turns into: 63 | 64 | ```haskell 65 | forall a b . a -> b -> a 66 | ``` 67 | 68 | # Currying still applies 69 | 70 | WHEN DID THIS 71 | 72 | ```haskell 73 | forall a b . a -> b -> a 74 | ``` 75 | 76 | BECOME MORE BEAUTIFUL THAN THIS? 77 | 78 | ```haskell 79 | forall a. a -> (forall b. b -> a) 80 | ``` 81 | 82 | # But yeah, same deal. 83 | 84 | ```haskell 85 | forall a b . a -> b -> a 86 | -- equivalent. 87 | forall a. a -> (forall b. b -> a) 88 | ``` 89 | 90 | # ExplicitForAll 91 | 92 | That was real syntax! You can write the foralls yourself! 93 | 94 | ```haskell 95 | {-# LANGUAGE ExplicitForAll #-} 96 | 97 | length :: forall a . a -> Int 98 | length = ... 99 | ``` 100 | 101 | # It seems like this should work 102 | 103 | `tuple.hs` 104 | 105 | # Tension! 106 | 107 | A tension between what terms can be permitted in our type system and what badness we can prevent. 108 | 109 | # Morality and legality are orthogonal 110 | 111 | There are programs we can write which are valid, but which a type system will reject. Part of PL and type theory research is making this valid-but-illegal space as small as possible. 112 | 113 | # Bad type system 114 | 115 | ![This type system is pain itself](painitself.png) 116 | 117 | # Good type system 118 | 119 | ![This type system is much nicer](muchnicer.png) 120 | 121 | # Rank-2 122 | 123 | # Higher rank polymorphism expansionism 124 | 125 | Higher rank polymorphism expands what our type system permits us to say, without any cost in correctness. 126 | 127 | # Examples from lens 128 | 129 | ```haskell 130 | {-# LANGUAGE Rank2Types #-} 131 | 132 | type Lens s t a b = 133 | forall f . Functor f => (a -> f b) -> s -> f t 134 | ``` 135 | 136 | # Rank-N 137 | 138 | `ranks.hs` 139 | -------------------------------------------------------------------------------- /rank_n_types_talk/rankn.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitemyapp/presentations/297b62546c72101d8a95f7933525041f2121cdf0/rank_n_types_talk/rankn.pdf -------------------------------------------------------------------------------- /rank_n_types_talk/ranks.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ExplicitForAll #-} 2 | {-# LANGUAGE RankNTypes #-} 3 | 4 | module Ranky where 5 | 6 | -- Examples from the GHC user documentation. 7 | 8 | -- Ordinary, rank-1 types with prenex form 9 | f1 :: forall a b . a -> b -> a 10 | f1 = undefined 11 | 12 | g1 :: forall a b . (Ord a, Eq b) => a -> b -> a 13 | g1 = undefined 14 | 15 | -- rank-2 type, needs rank2 or rankN pragma 16 | f2 :: (forall a . a -> a) -> Int -> Int 17 | f2 = undefined 18 | 19 | g2 :: (forall a . Eq a => [a] -> a -> Bool) -> Int -> Int 20 | g2 = undefined 21 | 22 | -- rank-3 type, needs rankN pragma 23 | f3 :: ((forall a . a -> a) -> Int) -> Bool -> Bool 24 | f3 = undefined 25 | -------------------------------------------------------------------------------- /rank_n_types_talk/tuple.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RankNTypes #-} 2 | 3 | module T where 4 | 5 | function :: (forall a . a -> a) -> (Int, String) -> (Int, String) 6 | function f (i, s) = (f i, f s) 7 | 8 | funct :: (Int, String) -> (Int, String) 9 | funct (i, s) = (id i, id s) 10 | 11 | addBoth :: (forall a . Num a => a -> a) -> (Int, Double) -> (Int, Double) 12 | addBoth f (i, d) = (f i, f d) 13 | 14 | -- explicit forall 15 | -- rank 2 / rank n 16 | -- type forall s t a b . Lens s t a b = 17 | --------------------------------------------------------------------------------