├── 2011 ├── 2011-12-18-haskell-nfa.md ├── 2011-12-21-static-vector-algebra.md └── 2011-12-27-template-haskell.md ├── 2012 ├── 2012-01-08-streams-coroutines.md ├── 2012-01-13-implementing-semantic-anti-templating-with-jquery.md ├── 2012-01-17-declarative-game-logic-afrp.md ├── 2012-02-17-concatenative-haskell.md └── 2012-02-21-concatenative-haskell-ii-dsl.md ├── 2013 ├── 2013-01-14-observable-sharing.md └── 2013-02-19-typesafe-tictactoe.md ├── LICENSE └── README.md /2011/2011-12-18-haskell-nfa.md: -------------------------------------------------------------------------------- 1 | # NFA in a Single Line of Haskell (aka. The List Monad is Awesome) 2 | 3 | [Nondeterministic finite automata][1] are most often used in the context of regular languages, and while the efficient approach in most practical applications is to translate the NFA to an equivalent [deterministic finite automaton][3], simulating the non-determinism directly makes for an interesting coding problem. In Haskell, it turns out we can leverage the power of the list monad to implement an NFA almost trivially. 4 | 5 | A nondeterministic finite automaton is defined in terms of 6 | 7 | * the initial state 8 | * a set of accepting states 9 | * a transition function, which takes a state and an input symbol and returns all possible next states 10 | 11 | Given the above, we can define an NFA type in Haskell as 12 | 13 | ```haskell 14 | data NFA q s = NFA 15 | { intialState :: q 16 | , isAccepting :: q -> Bool 17 | , transition :: q -> s -> [q] 18 | } 19 | ``` 20 | 21 | Note that the types for state and input grammar are generic, so we don't have to care about their internal representations. 22 | 23 | To test whether a given NFA accepts the given input, we want to write a function which takes an NFA and a list of input symbols and returns whether the NFA accepts the input or not. 24 | 25 | ```haskell 26 | testNFA :: NFA q s -> [s] -> Bool 27 | ``` 28 | 29 | Because of nondeterminism (i.e. each transition can lead to several possible states), the implementation has to try different branches and backtrack if the current branch didn't hit an accept state at the end of input. In practice, we can achieve the same end result if we maintain a list of all possible states where we can be at any given point in the input. 30 | 31 | In the end, the actual implementation boils down to 32 | 33 | ```haskell 34 | testNFA (NFA i a t) = any a . foldM t i 35 | ``` 36 | 37 | At first glance, it might be hard to believe that this is actually a fully functioning NFA implementation. We can define a simple test grammar to try it out: 38 | 39 | ```haskell 40 | data State = Q1 | Q2 | Q3 | Q4 | Q5 deriving (Eq, Show) 41 | data Symbol = A | B | C | D deriving (Eq, Show) 42 | 43 | -- initial state 44 | i = Q1 45 | 46 | -- accept criteria 47 | a = (`elem` [Q4,Q5]) 48 | 49 | -- state transitions 50 | t Q1 A = [Q2] 51 | t Q2 A = [Q3,Q4] 52 | t Q2 B = [Q1,Q2] 53 | t Q2 C = [Q3,Q4] 54 | t Q3 D = [Q5] 55 | t Q4 A = [Q2,Q4] 56 | t _ _ = [] 57 | 58 | nfa = NFA i a t 59 | ``` 60 | 61 | Now we can test different input sequences to see whether they are accepted by our grammar. 62 | 63 | ``` 64 | *Main> testNFA nfa [A,B,C,D] 65 | True 66 | *Main> testNFA nfa [A,A,B,B] 67 | False 68 | ``` 69 | 70 | So what actually happens? The real workhorse here is obviously `foldM` (from module `Control.Monad`). It does a [left fold][2] over a list using a monadic function, which in our case is the transition function *f*. We take advantage of the fact that lists are monads, and indeed, if we had a deterministic finite automaton, where the transition function had the type `q -> s -> q` (i.e. each transition only has one possible next state), we could write the function using a regular left fold. 71 | 72 | ```haskell 73 | testDFA (DFA i a t) = a . foldl t i 74 | ``` 75 | 76 | For NFAs, the accumulator for the the fold function is still the current state, but the transition function returns a list of states which is clearly incompatible with the regular `foldl`, but as we can see from the signatures, `foldM` matches our use-case perfectly. 77 | 78 | ```haskell 79 | foldl :: (a -> b -> a) -> a -> [b] -> a 80 | 81 | foldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a 82 | ``` 83 | 84 | The standard implementation of `foldM` calls the given monadic function with the initial value of the accumulator and the first item in the list, and then uses the monadic bind operator `>>=` to call itself recursively. 85 | 86 | ```haskell 87 | foldM _ a [] = return a 88 | foldM f a (x:xs) = f a x >>= \fax -> foldM f fax xs 89 | ``` 90 | 91 | For the list monad, the bind operator works so that `xs >>= f` feeds every value of list `xs` to the function `f` and then concatenates the results. So, for example, given the example transition function we defined earlier, calling 92 | 93 | ```haskell 94 | [Q1] >>= \q -> f q A 95 | ``` 96 | 97 | is the same thing as just calling `f Q1 A` 98 | 99 | but calling 100 | 101 | ```haskell 102 | [Q1,Q2] >>= \q -> f q A 103 | ``` 104 | 105 | concatenates all the possible next states from both `f Q1 A` and `f Q2 A`. 106 | 107 | Now as we look back to the implementation of `testNFA`, we can see that for each symbol in the input list, foldM feeds the list of possible states we could be in now to the transition function using the bind operator of the list monad, resulting in the list of all possible states where the current input symbol could take us. 108 | 109 | The final result form the `foldM` is the list of all possible states that we could be in when the input is fully consumed. This list is then compared against our accept criterion with `any a` to determine whether the input was valid. 110 | 111 | One more thing worth mentioning is that the state transition function can use some other monadic context besides the list monad. For example, in a recent Lambda-Saturday meet up, we implemented a [probability distribution monad][4] as an exercise, and used that to implement a [probabilistic automaton][5]. 112 | 113 | [1]: http://en.wikipedia.org/wiki/Nondeterministic_finite-state_machine 114 | [2]: http://en.wikipedia.org/wiki/Fold_(higher-order_function)#Folds_on_lists 115 | [3]: http://en.wikipedia.org/wiki/Deterministic_finite_automaton 116 | [4]: https://github.com/leonidas/lambda-5/blob/master/Data/Prob.hs 117 | [5]: https://github.com/leonidas/lambda-5/blob/master/pa.hs 118 | -------------------------------------------------------------------------------- /2011/2011-12-21-static-vector-algebra.md: -------------------------------------------------------------------------------- 1 | # Statically Typed Vector Algebra Using Type Families 2 | 3 | I've never used [type families](http://www.haskell.org/haskellwiki/GHC/Type_families) in Haskell before, but I've wanted to learn about them for a long time now, so I decided to get my feet wet and implement some sort of toy library that takes advantage of the new features the syntax allows. 4 | 5 | So let that be a disclaimer: I'm a complete newbie with type families and there is a high likelihood that any code below is unidiomatic and/or just plain bad. :) 6 | 7 | ## A More Flexible Num Class 8 | 9 | One particular thing that always bothered me in Haskell when I started learning it was the [`Num`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#t:Num) typeclass, which only allows arithmetic operations on two `Num` instances if they have the same type. This is fine for plain numbers, but it would be nice to be able to overload the standard numeric operators to work between, for example, numbers and vectors or vectors and matrices. 10 | 11 | Defining such heterogeneous operators has been possible for a long time using the language extensions [`MultiParamTypeClasses`](http://www.haskell.org/haskellwiki/Multi-parameter_type_class) and [`FunctionalDependencies`](http://www.haskell.org/haskellwiki/Functional_dependencies), but type families make it even nicer, in my opinion. 12 | 13 | So, let's get started. 14 | 15 | ```haskell 16 | {-# LANGUAGE TypeFamilies, MultiParamTypeClasses #-} 17 | 18 | module Data.Algebra where 19 | 20 | import Prelude hiding (Num(..)) 21 | import qualified Prelude as P 22 | ``` 23 | 24 | We'll hide the built-in `Num` typeclass and all its functions, and re-import `Prelude` so that we can access the original functions with the prefix `P.` when needed. We'll then break down the functionality of the `Num` typeclass to smaller parts, because not all type combinations support all operations. For example, matrices and vectors can be multiplied together, but not added. The `LANGUAGE` pragma enables the type families and multi-param typeclasses language extensions. 25 | 26 | ## Defining Addition Using an Associated Type Synonym 27 | 28 | Let's first declare the typeclass for types that support addition. 29 | 30 | ```haskell 31 | class Add a b where 32 | type AddResult a b 33 | 34 | (+) :: a -> b -> AddResult a b 35 | ``` 36 | 37 | One thing that the type families extension lets us do is to declare that some type varies in the different instances of the type class. So the type declaration `type AddResult a b` inside the typeclass means that AddResult is a type alias for some actual type, which depends on the generic types `a` and `b` and which needs to be specified in the instances of this typeclass. 38 | 39 | Integers can be added together, so let's define an instance for `Int`. 40 | 41 | ```haskell 42 | instance Add Int Int where 43 | type AddResult Int Int = Int 44 | 45 | (+) = (P.+) 46 | ``` 47 | 48 | Here we are saying that the result of the addition between two ints is an int. For the implementation of the addition operator, we just use the (+) from `Prelude`. 49 | 50 | You can think of `AddResult` as a sort of function that operates on types. It takes two types as parameters and returns a new type. 51 | 52 | Now, we could define an instance of `Add` for all number types, such as floats, doubles etc. by hand, but that would be too tedious. We can simply declare that any type that is a `Num` automatically supports addition. So let's replace the above type instance with a more generic one. 53 | 54 | ```haskell 55 | instance P.Num n => Add n n where 56 | type AddResult n n = n 57 | 58 | (+) = (P.+) 59 | ``` 60 | 61 | In order to compile this, you need to enable the `FlexibleInstances` language extension. 62 | 63 | This added genericity comes with a downside, however. Number literals in Haskell are a bit special in that if no explicit type is given, the compiler picks a suitable type for the literal. This allows us to do e.g. 64 | 65 | ``` 66 | Prelude> 1 + 2.5 67 | 3.5 68 | ``` 69 | 70 | Because the compiler will decide that the literal `1` is actually a double in this context. 71 | 72 | However, with the more generic `Add` typeclass, the compiler can no longer decide what the actual types of literals should be, because `Int + Float` might have a completely different implementation than `Float + Float`. So unfortunately, we will have to annotate all literals with explicit types when using these new typeclasses. 73 | 74 | ```haskell 75 | *Data.Algebra> (1::Float) + (2.5::Float) 76 | 3.5 77 | ``` 78 | 79 | Multiplication for number types is straightforward after implementing `Add`. 80 | 81 | ```haskell 82 | class Mul a b where 83 | type MulResult a b 84 | 85 | (*) :: a -> b -> MulResult a b 86 | 87 | instance P.Num n => Mul n n where 88 | type MulResult n n = n 89 | 90 | (*) = (P.*) 91 | ``` 92 | 93 | For division, we can make a special case for int division, so that it actually returns rational numbers. 94 | 95 | ```haskell 96 | import Data.Ratio (Ratio, (%)) 97 | 98 | class Div a b where 99 | type DivResult a b 100 | 101 | (/) :: a -> b -> DivResult a b 102 | 103 | instance Div Float Float where 104 | type DivResult Float Float = Float 105 | 106 | (/) = (P./) 107 | 108 | instance Div Int Int where 109 | type DivResult Int Int = Ratio Int 110 | 111 | (/) = (%) 112 | ``` 113 | 114 | It is unfortunate that we cannot simply create generic instances for all types that implement `Fractional` or `Integral`, because that would lead to ambiguities since you could, in theory, declare a type that implements both. 115 | 116 | We can now test the instances and see that the result of division correctly depends on the operand types. 117 | 118 | ``` 119 | *Data.Algebra> (1::Float) / (2::Float) 120 | 0.5 121 | *Data.Algebra> (1::Int) / (2::Int) 122 | 1 % 2 123 | ``` 124 | 125 | ## Vectors 126 | 127 | Let's implement a vector type using arrays. 128 | 129 | ```haskell 130 | import Data.Array.Unboxed 131 | 132 | newtype Vector = Vector { vecArray :: UArray Int Float } 133 | ``` 134 | 135 | Vectors can be multiplied by scalars. 136 | 137 | ```haskell 138 | instance Mul Float Vector where 139 | type MulResult Float Vector = Vector 140 | 141 | x * (Vector v) = Vector . amap (P.* x) $ v 142 | ``` 143 | 144 | In order to test the multiplication, we'll define a constructor and a `Show` instance for vectors. 145 | 146 | ```haskell 147 | vector2d :: Float -> Float -> Vector 148 | vector2d x y = Vector $ listArray (1,2) [x,y] 149 | 150 | instance Show Vector where 151 | show = show . elems . vecArray 152 | ``` 153 | 154 | ``` 155 | *Data.Algebra> (1.5::Float) * vector2d 3.0 4.0 156 | [4.5,6.0] 157 | ``` 158 | 159 | Addition between two vectors adds them element-wise, but addition can only be performed between vectors that have the same number of components. 160 | 161 | It would be really nice if the type system enforced this somehow for vectors with known dimensionality, and it turns out we can achieve this quite easily using [phantom types](http://www.haskell.org/haskellwiki/Phantom_type). 162 | 163 | A phantom type is essentially a type parameter of a parametric data type that is not used in the actual type definition. E.g. 164 | 165 | ```haskell 166 | newtype Vector d = Vector { vecArray :: UArray Int Float } 167 | ``` 168 | 169 | Here the `Vector` type has a parameter `d` for dimensionality, but its internal structure doesn't use this type information in any way. We can use empty types for annotating dimensionality using the language extension [`EmptyDataDecls`](http://www.haskell.org/haskellwiki/Empty_type). 170 | 171 | ```haskell 172 | data D1 173 | data D2 174 | data D3 175 | ``` 176 | 177 | We can now add more precise type signatures. 178 | 179 | ```haskell 180 | vector2d :: Float -> Float -> Vector D2 181 | vector2d x y = Vector $ listArray (1,2) [x,y] 182 | 183 | vector3d :: Float -> Float -> Float -> Vector D3 184 | vector3d x y z = Vector $ listArray (1,3) [x,y,z] 185 | 186 | instance Mul Float (Vector d) where 187 | type MulResult Float (Vector d) = (Vector d) 188 | 189 | x * (Vector v) = Vector . amap (P.* x) $ v 190 | 191 | instance Show (Vector d) where 192 | show = show . elems . vecArray 193 | ``` 194 | 195 | The constructors now return vectors of specific dimensionality, and the multiplication explicitly declares that the operation doesn't change the number of dimensions. Now we can implement vector addition so that we have a compile-time type check that ensures we can only add vectors that have the same length. 196 | 197 | ```haskell 198 | instance Add (Vector d) (Vector d) where 199 | type AddResult (Vector d) (Vector d) = Vector d 200 | 201 | (Vector a) + (Vector b) = Vector $ listArray bds els where 202 | bds = bounds a 203 | els = zipWith (P.+) (elems a) (elems b) 204 | ``` 205 | 206 | However, this instance declaration overlaps with the existing instance `Num n => Add n n` (I assume this is because somebody might create a `Num` instance for vectors), so we need to add yet another language extension: [`OverlappingInstances`](http://www.haskell.org/haskellwiki/GHC/AdvancedOverlap) 207 | 208 | Let's see how it works: 209 | 210 | ``` 211 | *Data.Algebra> vector2d 2.0 3.0 + vector2d 3.0 4.0 212 | [5.0,7.0] 213 | *Data.Algebra> vector2d 2.0 3.0 + vector3d 1.0 2.0 3.0 214 | 215 | :1:18: 216 | No instance for (Add (Vector D2) (Vector D3)) 217 | arising from a use of `+' 218 | Possible fix: 219 | add an instance declaration for (Add (Vector D2) (Vector D3)) 220 | In the expression: vector2d 2.0 3.0 + vector3d 1.0 2.0 3.0 221 | In an equation for `it': 222 | it = vector2d 2.0 3.0 + vector3d 1.0 2.0 3.0 223 | ``` 224 | 225 | That's exactly what we wanted! A compiler error when we try to add 2D and 3D vectors together. 226 | 227 | 228 | ## Matrices 229 | 230 | Matrices can be implemented like vectors, but with two dimension parameters. 231 | 232 | ```haskell 233 | newtype Matrix m n = Matrix { matArray :: UArray (Int,Int) Float } 234 | ``` 235 | 236 | The matrix multiplication *A x B* is only valid if the dimensions of matrices A and B are *m x p* and *p x n*, which results in a *m x n* matrix. This can be defined very naturally with our associated type. 237 | 238 | ```haskell 239 | instance Mul (Matrix m p) (Matrix p n) where 240 | type MulResult (Matrix m p) (Matrix p n) = Matrix m n 241 | 242 | (Matrix a) * (Matrix b) = Matrix $ listArray bds els where 243 | bds = ((1,1),(m,n)) 244 | els = el <$> [1..m] <*> [1..n] 245 | 246 | el i j = sum [a!(i,k) * b!(k,j) | k <- [1..p]] 247 | 248 | (_,(m,p)) = bounds a 249 | (_,(_,n)) = bounds b 250 | ``` 251 | 252 | Multiplying matrices and vectors together is, again, a bit ambiguous because we might want to use the vector either as a row-vector or a column-vector. So let's make our intention explicit. 253 | 254 | ```haskell 255 | row :: Vector d -> Matrix D1 d 256 | row (Vector v) = Matrix $ ixmap ((1,1),(1,n)) (\(1,j) -> j) v where 257 | (_,n) = bounds v 258 | 259 | col :: Vector d -> Matrix d D1 260 | col (Vector v) = Matrix $ ixmap ((1,1),(m,1)) (\(i,1) -> 1) v where 261 | (m,_) = bounds v 262 | ``` 263 | 264 | Here, again, the mere type-signatures of the functions describe their behavior wonderfully. 265 | 266 | 267 | ## Type Algebra 268 | 269 | Constructing matrices poses the problem that if we need to write an explicit constructor for every size combination, that'll be a lot of tedious work. One option is to construct vectors and matrices from small pieces, one dimension at a time. 270 | 271 | However, to do that, we need to do more than just tag dimensionality with empty types. We need to somehow express the relation between types such as `D2` and `D3`. 272 | 273 | The so called [Peano axioms](http://en.wikipedia.org/wiki/Peano_axioms) define natural numbers in terms of *zero* and *S(n)* where *S(n)* is the successor for any natural number *n*. So, for example, the natural number one is defined as *S(zero)* and the number two is *S(S(zero))* and so on. We can use a similar system to establish relations between the different dimensionalities. 274 | 275 | ```haskell 276 | data D1 277 | data Succ d 278 | type D2 = Succ D1 279 | type D3 = Succ D2 280 | ``` 281 | 282 | We disallow vectors with zero dimensions, so we start with `D1` and define each following dimensionality in terms of `D1` and `Succ`. 283 | 284 | Now we can define a builder operation that prepends new dimensions to vectors and matrices. 285 | 286 | ```haskell 287 | class Cons e c where 288 | type ConsResult e c 289 | 290 | (+:) :: e -> c -> ConsResult e c 291 | 292 | instance Cons Float (Vector d) where 293 | type ConsResult Float (Vector d) = Vector (Succ d) 294 | 295 | x +: (Vector v) = Vector . listArray bds . (x:) . elems $ v where 296 | bds = second succ $ bounds v 297 | ``` 298 | 299 | Again, thanks to type families, we are able to encode at type level, that prepending a new element to a vector increases its dimensionality by one. 300 | 301 | For matrices, we'll cons row-vectors. 302 | 303 | ```haskell 304 | instance Cons (Vector n) (Matrix m n) where 305 | type ConsResult (Vector n) (Matrix m n) = Matrix (Succ m) n 306 | 307 | (Vector a) +: (Matrix b) = Matrix $ listArray bds els where 308 | bds = second (second succ) $ bounds b 309 | els = elems a ++ elems b 310 | ``` 311 | 312 | Now we can build matrices of any size from vectors and still have the dimensions statically checked. 313 | 314 | ```haskell 315 | *Data.Algebra> let a = vector3d 1 2 3 316 | *Data.Algebra> let b = vector3d 4 5 6 317 | *Data.Algebra> let c = vector3d 7 8 9 318 | 319 | *Data.Algebra> let m = a +: b +: row c 320 | *Data.Algebra> m 321 | [1.0,2.0,3.0] 322 | [4.0,5.0,6.0] 323 | [7.0,8.0,9.0] 324 | 325 | *Data.Algebra> :t m 326 | m :: Matrix (Succ (Succ D1)) (Succ D2) 327 | ``` 328 | 329 | While ghci doesn't always show us the nice type aliases, we can easily see that the type of the resulting matrix is indeed equal to `Matrix D3 D3`. 330 | 331 | 332 | ## Statically Typed Concatenation 333 | 334 | What if we want to concatenate two vectors together? How do we maintain the type information then? 335 | 336 | ```haskell 337 | class Concat a b where 338 | type ConcatResult a b 339 | 340 | (++:) :: a -> b -> ConcatResult a b 341 | ``` 342 | 343 | Now the dimensionality of the resulting vector needs to be the sum of the dimensionalities of the two operand vectors, and as crazy as it sounds, we can actually perform arithmetic operations with the types themselves. 344 | 345 | ```haskell 346 | class AddT a b where 347 | type AddTResult a b 348 | 349 | instance AddT D1 a where 350 | type AddTResult D1 a = Succ a 351 | 352 | instance AddT (Succ a) b where 353 | type AddTResult (Succ a) b = AddTResult a (Succ b) 354 | ``` 355 | 356 | Unfortunately, this kind of type manipulation opens up another can of worms and, again, we need a new extension: [`UndecidableInstances`](http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#undecidable-instances). 357 | 358 | However, now we can implement concatenation with proper types. 359 | 360 | ```haskell 361 | instance Concat (Vector a) (Vector b) where 362 | type ConcatResult (Vector a) (Vector b) = Vector (AddTResult a b) 363 | 364 | (Vector a) ++: (Vector b) = Vector $ listArray bds els where 365 | bds = (\(_,i)(_,j) -> (1,i+j)) (bounds a) (bounds b) 366 | els = elems a ++ elems b 367 | ``` 368 | 369 | Let's test that the type-checker allows operations between vectors that have been built in different ways: 370 | 371 | ``` 372 | *Data.Algebra> let v = (vector2d 1 2 ++: vector2d 3 4) + ((1::Float) +: vector3d 2 3 4) 373 | *Data.Algebra> v 374 | [2.0,4.0,6.0,8.0] 375 | *Data.Algebra> :t v 376 | v :: Vector (Succ (Succ (Succ D1))) 377 | ``` 378 | 379 | ## Statically Checked Indexing 380 | 381 | One more thing we can do is to ensure that when we access vector components, the index is verified to be valid during compile time. This will unfortunately require some plumbing (let me know if you can come up with a simpler way!). 382 | 383 | ```haskell 384 | data Get d = Safe 385 | 386 | getPrev :: Get (Succ d) -> Get d 387 | getPrev _ = Safe 388 | 389 | class GetIndex g where 390 | getIndex :: g -> Int 391 | 392 | instance GetIndex (Get D1) where 393 | getIndex = const 1 394 | 395 | instance GetIndex (Get d) => GetIndex (Get (Succ d)) where 396 | getIndex = (P.+ 1) . getIndex . getPrev 397 | ``` 398 | 399 | Now we have a type that can map the dimensionality types to array indices. 400 | 401 | We'll start with the simple case, i.e. it is always safe to index a vector with a value that is equal to the vector's dimensionality. 402 | 403 | ```haskell 404 | class SafeGet g c where 405 | type GetElem c 406 | 407 | (!!!) :: c -> g -> GetElem c 408 | 409 | instance GetIndex (Get d) => SafeGet (Get d) (Vector d) where 410 | type GetElem (Vector d) = Float 411 | 412 | Vector v !!! g = v ! getIndex g 413 | ``` 414 | 415 | Now we can index, for example, a two element vector with the type `D2`. 416 | 417 | ``` 418 | *Data.Algebra> let v = vector2d 1 2 419 | *Data.Algebra> v !!! (Safe::Get D2) 420 | 2.0 421 | ``` 422 | 423 | but indexing with `D1` doesn't match our instance declaration. 424 | 425 | ``` 426 | *Data.Algebra> v !!! (Safe::Get D1) 427 | 428 | :1:3: 429 | No instance for (SafeGet (Get D1) (Vector D2)) 430 | arising from a use of `!!!' 431 | Possible fix: 432 | add an instance declaration for (SafeGet (Get D1) (Vector D2)) 433 | In the expression: v !!! (Safe :: Get D1) 434 | In an equation for `it': it = v !!! (Safe :: Get D1) 435 | ``` 436 | 437 | What we really want to express is that indexing is safe whenever the indexing dimension is the same *or lower* than the vector's dimensionality. I.e. we need to be able to compare types and have type level conditionals. 438 | 439 | ```haskell 440 | data TTrue -- type level truth value 441 | 442 | -- type level less-or-equal 443 | class TLessEq x y where 444 | type IsLessEq x y 445 | 446 | -- D1 is equal to D1 447 | instance TLessEq D1 D1 where 448 | type IsLessEq D1 D1 = TTrue 449 | 450 | -- D1 is less than any successor type 451 | instance TLessEq D1 (Succ d) where 452 | type IsLessEq D1 (Succ d) = TTrue 453 | 454 | -- The ordering of x and y is the same as (Succ x) and (Succ y) 455 | instance TLessEq x y => TLessEq (Succ x) (Succ y) where 456 | type IsLessEq (Succ x) (Succ y) = IsLessEq x y 457 | ``` 458 | 459 | Now we can rewrite the `SafeGet` instance for vectors using the type operator `~` which declares that its two type operands must be equal. 460 | 461 | ```haskell 462 | -- Instance for all types (Get i) and (Vector d) for which i <= d 463 | instance (GetIndex (Get i), IsLessEq i d ~ TTrue) => SafeGet (Get i) (Vector d) where 464 | type GetElem (Vector d) = Float 465 | 466 | Vector v !!! g = v ! getIndex g 467 | ``` 468 | 469 | And we can then index two-dimensional vectors with D1 and D2, but get a compile-time error when indexing with D3. 470 | 471 | ``` 472 | *Data.Algebra> let v = vector2d 1 2 473 | *Data.Algebra> v !!! (Safe::Get D1) 474 | 1.0 475 | *Data.Algebra> v !!! (Safe::Get D2) 476 | 2.0 477 | *Data.Algebra> v !!! (Safe::Get D3) 478 | 479 | :1:3: 480 | Couldn't match type `IsLessEq (Succ D1) D1' with `TTrue' 481 | arising from a use of `!!!' 482 | In the expression: v !!! (Safe :: Get D3) 483 | In an equation for `it': it = v !!! (Safe :: Get D3) 484 | ``` 485 | 486 | The instance for safe matrix indexing is similar: 487 | 488 | ```haskell 489 | instance (GetIndex (Get i), GetIndex (Get j), IsLessEq i m ~ TTrue, IsLessEq j n ~ TTrue) 490 | => SafeGet (Get i, Get j) (Matrix m n) where 491 | 492 | type GetElem (Matrix m n) = Float 493 | 494 | Matrix m !!! (i,j) = m ! (getIndex i, getIndex j) 495 | ``` 496 | 497 | ## Vectors and Matrices of Arbitrary Size 498 | 499 | In order to be generic, we might also want to support unsafe vectors and matrices whose size is not known during compile-time. For that, we can define a type that represents unknown, arbitrary dimensionality and functions for type-casting safe values into unsafe values. 500 | 501 | ```haskell 502 | data Arb 503 | 504 | class ToArb a where 505 | type ArbResult a 506 | 507 | toArb :: a -> ArbResult a 508 | 509 | instance ToArb (Vector d) where 510 | type ArbResult (Vector d) = Vector Arb 511 | 512 | toArb (Vector v) = Vector v 513 | 514 | instance ToArb (Matrix m n) where 515 | type ArbResult (Matrix m n) = Matrix Arb Arb 516 | 517 | toArb (Matrix m) = Matrix m 518 | ``` 519 | 520 | Because how our instances are defined, expressions such as `(m :: Matrix Arb Arb) * (v :: Vector Arb)` type-check, but can trigger run-time errors. Now we can use the exact same library functions for handling vectors and matrices that are of unknown size. 521 | 522 | 523 | ## Conclusion 524 | 525 | I learned a lot of new things about Haskell's type system while writing this entry, and hopefully there were bits that were interesting for you too. 526 | 527 | While statically checked vectors and matrices might not be all that useful for general purpose computation, I think they could be very handy in application domains such as computer graphics, where you mostly work with 2D and 3D vectors and their transformation matrices. 528 | 529 | You could have, for example, a projection function with explicit types 530 | 531 | ```haskell 532 | project :: Matrix D3 D3 -> Vector D3 -> Vector D2 533 | ``` 534 | 535 | so that you know for certain that you are not mixing up screen coordinates with world coordinates somewhere. 536 | 537 | All the code written for this post can be viewed and downloaded [here](https://gist.github.com/1506540). 538 | 539 | ## Updates 540 | 541 | ### 2011-12-21 21:13 UTC 542 | 543 | The user ryani over at the [reddit thread](http://www.reddit.com/r/haskell/comments/nlctb/statically_typed_vector_algebra_with_type_families/) made a great point about `AddT`. Since the typeclass doesn't contain any methods, it doesn't make much sense to use a typeclass with associated types. You can simply use a top level type family, which also gets rid of the requirement for UndecidableInstances. This is a big deal, as the aforementioned extension has a lot of drawbacks. 544 | 545 | ```haskell 546 | type family AddT a b 547 | type instance AddT D1 b = Succ b 548 | type instance AddT (Succ a) b = Succ (AddT a b) 549 | ``` 550 | 551 | -- 552 | Sami Hangaslammi <[sami.hangaslammi@leonidasoy.fi](mailto://sami.hangaslammi@leonidasoy.fi)> 553 | 554 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 555 | -------------------------------------------------------------------------------- /2011/2011-12-27-template-haskell.md: -------------------------------------------------------------------------------- 1 | # Basic Tutorial of Template Haskell 2 | 3 | I've been trying to learn [Template Haskell](http://www.haskell.org/haskellwiki/Template_Haskell) lately, but finding easy to understand, up-to-date tutorial material seems to be somewhat of a challenge, so I decided to write down my experiences while trying to decipher the basics of Haskell meta-programming. 4 | 5 | The code in this post has been tested with GHC 7.10.3 and template-haskell 2.10.0.0. 6 | 7 | ## Quotations 8 | 9 | The essence of Template Haskell is to write Haskell code that generates new Haskell code. To ensure that the generated code is well structured, we don't generate Haskell source code, but instead generate the [abstract syntax trees](http://en.wikipedia.org/wiki/Abstract_syntax_tree) directly. So, for example, the function call `f x` is described by the syntax tree `AppE (VarE f) (VarE x)`. However, building the syntax trees manually for anything but the simplest expressions is a lot work, so Template Haskell makes the task easier with quotations. 10 | 11 | Quotations can be thought of as syntactic sugar for generating ASTs. There are several different kinds of quotations, depending on the context we are working in. 12 | 13 | * Expression quotations are used for generating regular Haskell expressions, and the have the syntax `[|expression|]`. So for example `[|1+2|]` is syntactic sugar for the infix expression `InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) (Just (LitE (IntegerL 2)))`. 14 | 15 | * Declaration quotations are used for generating top-level declarations for constants, types, functions, instances etc. and use the syntax `[d|declaration|]`. Example: `[d|x = 5|]` results in `[ValD (VarP f) (NormalB (LitE (IntegerL 5))) []]`. Note that the quotation can contain multiple declarations, so it evaluates to a list of declaration values. 16 | 17 | * Type quotations are used for generating type values, such as `[t|Int|]` 18 | 19 | * Pattern quotations are used for generating patterns which are used, for example, in function declarations and case-expressions. `[p|(x,y)|]` generates the pattern `TupP [VarP x,VarP y]`. 20 | 21 | * The last type is the so called "quasi-quotation", which lets us build our own, custom quotations, but these are a more advanced topic that won't be covered in this post. 22 | 23 | For simple tasks, we don't really need type and pattern quotations, because they can be generated as part of a larger expression or declaration quotation. For example: `[d|head' (x:_) = x|]` results in `[FunD head' [Clause [InfixP (VarP x_1) GHC.Types.: WildP] (NormalB (VarE x_1)) []]]`. 24 | 25 | The ASTs values generated using quotations are contained in the monad [`Q`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Syntax.html#t:Q). The `Q` monad handles such things as generating unique names and introspection of data types, but you don't really need to know anything about the inner workings of `Q`. The important thing is that declarations and expressions inside a `Q` monad can be used for "splicing" the generated ASTs into regular Haskell code. 26 | 27 | 28 | ## Example: Generating a Show Instance 29 | 30 | As a simple example, let's see how we could automatically generate `Show` instances for data types using Template Haskell. 31 | 32 | As a first step, we'll create a `Show` instance that always returns an empty string. 33 | 34 | ```haskell 35 | {-# LANGUAGE TemplateHaskell, FlexibleInstances #-} 36 | 37 | module CustomShow where 38 | 39 | import Language.Haskell.TH 40 | 41 | emptyShow :: Name -> Q [Dec] 42 | emptyShow name = [d|instance Show $(conT name) where show _ = ""|] 43 | ``` 44 | 45 | So given a name, we declare an instance for the type by that name where `show` always returns `""`. The `[d|` prefix denotes this as a declaration quotation, and inside the quotation, we use `$()` to splice in another quotation, `conT name`. The [`conT`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Lib.html#v:conT) function constructs a `Q Type` value from a name. 46 | 47 | (The language extension `FlexibleInstances` really shouldn't be needed here, but for some reason, splicing the declaration like we do here doesn't compile without it. I suspect it is because the `$()` splice in the instance declaration could potentially return a more complex type.) 48 | 49 | We'll then define a test data type in `test_show.hs`: 50 | 51 | ```haskell 52 | {-# LANGUAGE TemplateHaskell #-} 53 | 54 | import CustomShow 55 | 56 | data MyData = MyData 57 | { foo :: String 58 | , bar :: Int 59 | } 60 | 61 | emptyShow ''MyData 62 | 63 | main = print $ MyData { foo = "bar", bar = 5 } 64 | ``` 65 | 66 | Since the return type of `emptyShow` is `Q [Dec]` (i.e. a list of declarations in the `Q` monad), we can call it directly at the top-level of the module to insert the generated declarations there. The two single-quotes in `''MyData` are used for escaping a name. This is the same as calling `mkName "MyData"`. 67 | 68 | The `emptyShow` function has to be in a different file, because it needs to be already fully compiled at the point where we use it. 69 | 70 | ### Introspection Using reify 71 | 72 | In order to show the fields of a record type, we need to introspect the type declaration. This is done in Template Haskell using a function called [`reify`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Syntax.html#v:reify). It returns an [`Info`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Syntax.html#t:Info) value in the `Q` monad. 73 | 74 | ```haskell 75 | listFields :: Name -> Q [Dec] 76 | listFields name = do 77 | TyConI (DataD _ _ _ [RecC _ fields] _) <- reify name 78 | ``` 79 | 80 | The structure returned by `reify` is rather complex, but in this toy-example, we just pattern-match with the hard-coded assumption that `reify` returns a type constructor, which is a data declaration, which contains exactly one record type constructor. From that, we can get a list of record fields. If our assumptions do not hold for some type, we will get a compile-time error. 81 | 82 | The `fields` list contains `(name, strict, type)` tuples, but we are just interested in the field name for now, so let's separate that. 83 | 84 | ```haskell 85 | let names = map (\(name,_,_) -> name) fields 86 | ``` 87 | 88 | Next, we are going to build a quotation for a function that takes a record and shows the name and value of a specific field. 89 | 90 | ```haskell 91 | let showField :: Name -> Q Exp 92 | showField name = [|\x -> s ++ " = " ++ show ($(varE name) x)|] where 93 | s = nameBase name 94 | ``` 95 | 96 | We use the expression quotation to generate a lambda function that returns the string "*name* = *value*". The content of the quotation is just regular Haskell code, except for the splice `$(varE name)`, which is used to access the getter function for the specific named field. It is also noteworthy that we are able use the local variable `s` inside the quotation as is. In the generated AST, it will come out as a plain string literal. 97 | 98 | Now that we can generate code for showing a single field, we simply need to iterate all the different field names. 99 | 100 | ```haskell 101 | let showFields :: Q Exp 102 | showFields = listE $ map showField names 103 | ``` 104 | 105 | The [`listE`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Lib.html#v:listE) utility function takes a list of expression quotations `[Q Exp]` and turns that into a single expression that returns a list. So, given a list of quotations that all generate a function of type `a -> String` we get a quotation for a list literal of type `[a -> String]`. 106 | 107 | Finally, we declare the `Show` instance itself with a declaration quotation. 108 | 109 | ```haskell 110 | [d|instance Show $(conT name) where 111 | show x = intercalate ", " (map ($ x) $showFields)|] 112 | ``` 113 | 114 | As you can see, the Template Haskell language extension makes the `$` operator context sensitive. In order to use it as a function application operator (like in `map ($ x)`, it needs to be surrounded by space, otherwise it is interpreted as a splicing operator by Template Haskell (as in `$showFields`). 115 | 116 | Other than having to prefix the identifier with `$`, you can treat `showFields` just like any other list value. Here we map over the list, and pass `x` (which is the record object we are trying to show) to each function in the list. This results in a list of strings, which we intercalate with the separator `", "`. 117 | 118 | Now we have a custom Show-macro that can be used to print out the fields of any record type. 119 | 120 | ```haskell 121 | > print $ MyData { foo = "bar", bar = 5 } 122 | foo = "bar", bar = 5 123 | ``` 124 | 125 | ## Conclusion 126 | 127 | There's much more to Template Haskell, but hopefully this will get you started. I've focused on the things that I feel are the most important hurdles in the beginning for most Template Haskell users, namely, expression quotations, declaration quotations, splicing and introspecting record data types. Quasi-quotes will be covered in more detail in a future blog post. 128 | 129 | All the code in this entry can be viewed and downloaded [here](https://gist.github.com/1524967). 130 | 131 | You can discuss this entry on [Reddit](http://www.reddit.com/r/haskell/comments/nsmq0/basic_tutorial_of_template_haskell/). 132 | 133 | -- 134 | Sami Hangaslammi <[sami.hangaslammi@leonidasoy.fi](mailto://sami.hangaslammi@leonidasoy.fi)> 135 | 136 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 137 | 138 | -------------------------------------------------------------------------------- /2012/2012-01-08-streams-coroutines.md: -------------------------------------------------------------------------------- 1 | # Generalizing Streams into Coroutines 2 | 3 | In programming, the term "[stream][1]" is usually used to mean a sequence of values that is generated on-demand. In type theory and functional programming, it commonly refers specifically to infinite sequences. 4 | 5 | In a lazy language like Haskell, defining an infinite stream of values is straightforward. 6 | 7 | ```haskell 8 | data Stream a = Stream a (Stream a) 9 | ``` 10 | 11 | i.e. a stream of values (of type a) consists of the first value and the rest of the stream, just like a non-empty list consists of its head and tail. 12 | 13 | We can then define, for example, a stream of increasing integer values starting from some *n*. 14 | 15 | ```haskell 16 | intsFrom :: Integer -> Stream Integer 17 | intsFrom n = Stream n $ intsFrom $ n + 1 18 | ``` 19 | 20 | If you tried to naively implement the same thing in a non-lazy language like Python 21 | 22 | ```python 23 | def intsFrom(n): 24 | return (n, intsFrom(n+1)) 25 | ``` 26 | 27 | you would get an infinite recursion and overflow the call-stack. 28 | 29 | One way to simulate laziness in a non-lazy language is to use explicit function calls to defer evaluation. So in Python, we could define that a stream is a function that returns a value and a new function for getting the rest of the stream. 30 | 31 | ```python 32 | def intsFrom(n): 33 | return lambda: (n, intsFrom(n+1)) 34 | ``` 35 | 36 | Now we can evaluate the stream one item at a time. 37 | 38 | ``` 39 | >>> intsFrom(1)() 40 | (1, at 0x02B90D70>) 41 | >>> _[1]() 42 | (2, at 0x02B90D30>) 43 | >>> _[1]() 44 | (3, at 0x02B90D70>) 45 | ``` 46 | 47 | If Haskell was a strict language, we could use a similar approach to implement the infinite stream type. 48 | 49 | ```haskell 50 | data Stream a = Stream (() -> (a, Stream a)) 51 | 52 | intsFrom n = Stream $ \() -> (n, intsFrom (n+1)) 53 | ``` 54 | 55 | This is essentially identical to the Python implementation. 56 | 57 | Now let's return to the regular, lazy Haskell. Even with laziness, the above pattern might prove useful if we generalize it a bit. Since we already have a function that continues the stream, why not use that function call to pass some relevant information back to the stream generator that can alter the course of the stream, i.e. 58 | 59 | ```haskell 60 | data Stream b a = Stream (b -> (a, Stream b a)) 61 | ``` 62 | 63 | Now we are able to construct streams where the consumer of the stream can feed information back to the generator of the stream at every step. Our stream type essentially becomes a kind of [coroutine][2]. However, unlike normal coroutines, this kind of coroutine never terminates, so it can always be resumed. 64 | 65 | Since we only have a single constructor with a single parameter, it's more idiomatic (and efficient) in Haskell to represent the type as a `newtype`. 66 | 67 | ```haskell 68 | newtype Coroutine i o = Coroutine { runC :: i -> (o, Coroutine i o) } 69 | ``` 70 | 71 | Here *i* is the input type of the coroutine and *o* is the type of the output. We can use `runC` to call the coroutine. 72 | 73 | So, just to recap. Whereas a normal function from input to output would have the type `i -> o`, the coroutine returns, for every invocation, an output value as well as a new coroutine. From the caller's point of view, using coroutine usually means calling the coroutine (using `runC`), then discarding the original coroutine and calling the new coroutine with the next input value. I.e. 74 | 75 | ```haskell 76 | let (output1, newCo) = runC co input1 77 | (output2, newerCo) = runC newCo input2 78 | ``` 79 | 80 | Of course, you would normally use e.g. recursion instead of manually assigning the different versions of `co`. 81 | 82 | The property which makes coroutines interesting as a control structure is that at each step, both the coroutine and its caller can make branching decisions based on input and output respectively. 83 | 84 | 85 | ## Coroutines as Functors 86 | 87 | Whenever you implement a new parametric data type in Haskell, it's beneficial to consider whether it fits any of the commonly used abstractions. Providing instances for the many standard type-classes will immediately give you a lot of functionality for practically free, and what's best, it will be easy to understand for users that are already well acquainted with these abstractions. 88 | 89 | A functor is, simply put, any parametric type `T a` which you can map into `T b` using a function `a -> b`. This usually means a collection type like list, where you can turn `[a]` into `[b]` by applying a function `a -> b` for each element (i.e. [`map`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-List.html#v:map)), but functors are not limited to collections. 90 | 91 | For coroutines, a functor instance needs to implement `fmap :: (a -> b) - > Coroutine i a -> Coroutine i b`. 92 | 93 | ```haskell 94 | instance Functor (Coroutine i) where 95 | fmap f co = Coroutine $ \i -> 96 | let (o, co') = runC co i 97 | in (f o, fmap f co') 98 | ``` 99 | 100 | The implementation itself is very simple. Whenever the fmapped coroutine gets an input value, it calls the original coroutine and then applies *f* to the output value and `fmap f` recursively to the continuation. 101 | 102 | Note that we are specifically declaring `Coroutine i` to be an instance of functor so that `fmap (a -> b)` maps from `Coroutine i a` to `Coroutine i b`, i.e. the input type of the coroutine stays the same. 103 | 104 | 105 | ## Coroutines as Applicative Functors 106 | 107 | Using `fmap`, you can apply a function of type `a -> b` to a `Coroutine i a`, but what if you had a function of type `a -> b -> c`? If you use `fmap` like before, you end up with with a result of type `Coroutine i (b -> c)`. In order to feed in the second parameter `b`, we need a more powerful abstraction: applicative functor. 108 | 109 | Applicative functors are functors that have two additional properties. A parametric type `T a` is an applicative functor if: 110 | 111 | * You can put any "pure" value inside T, i.e. you have a function `a -> T a` 112 | * You can apply a function that is inside T to a value that is inside T, i.e. you have a function `T (a -> b) -> T a -> T b` 113 | 114 | In Haskell, the above two functions are called `pure` and `<*>`. 115 | 116 | 117 | ```haskell 118 | instance Applicative (Coroutine i) where 119 | pure x = Coroutine $ const (x, pure x) 120 | 121 | cof <*> cox = Coroutine $ \i -> 122 | let (f, cof') = runC cof i 123 | (x, cox') = runC cox i 124 | in (f x, cof' <*> cox') 125 | ``` 126 | 127 | For coroutines, the implementation of `pure` turns a constant value into a coroutine that returns that value for every invocation of the coroutine. `<*>` composes two coroutines `cof :: Coroutine i (x -> y)` and `cox :: Coroutine i x` into a new coroutine of type `Coroutine i y`. So the first coroutine produces functions and the second produces values that are applied to the functions. 128 | 129 | The two coroutines both get the same input values and advance in lock-step fashion, so if we were to feed in the inputs *i1*, *i2* and *i3*, *cof* and *cox* would produce the functions *f1*, *f2* and *f3* and the values *x1*, *x2* and *x3* respectively. The final outputs of the combined coroutine would be the result values from the function applications *f1(x1)*, *f2(x2)* and *f3(x3)*. 130 | 131 | Next we'll define a convenience function that lets us test our coroutines by feeding them a list of input values and returning the outputs. 132 | 133 | ```haskell 134 | evalList :: Coroutine i o -> [i] -> [o] 135 | evalList _ [] = [] 136 | evalList co (x:xs) = o:evalList co' xs 137 | where (o, co') = runC co x 138 | ``` 139 | 140 | As the simplest example, let's re-implement the `intsFrom` stream as a coroutine that ignores its input and test our functor and applicative implementations. 141 | 142 | ```haskell 143 | intsFrom :: Integer -> Coroutine () Integer 144 | intsFrom n = Coroutine $ \_ -> (n, intsFrom (n+1)) 145 | ``` 146 | 147 | ``` 148 | *Main> let i = intsFrom 5 149 | *Main> evalList i [(),(),()] 150 | [5,6,7] 151 | *Main> let i2 = fmap (*2) i 152 | *Main> evalList i2 [(),(),()] 153 | [10,12,14] 154 | *Main> let z = (,) <$> i <*> i2 155 | *Main> evalList z [(),(),()] 156 | [(5,10),(6,12),(7,14)] 157 | ``` 158 | 159 | (the operator `<$>` is an alias for `fmap`) 160 | 161 | 162 | ## Coroutines as Arrows 163 | 164 | The [`Category`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Category.html#t:Category) type-class can be thought of as a generalization of the function arrow `->`. 165 | 166 | The `Category` instance for coroutines defines an identity coroutine `id :: Coroutine a a`, which just returns every input value unchanged. The other function in the type-class is the composition operator `.`, which lets us compose two coroutines into one, just like we do with regular function composition. 167 | 168 | ```haskell 169 | import Prelude hiding (id, (.)) 170 | 171 | import Control.Arrow 172 | import Control.Category 173 | 174 | instance Category Coroutine where 175 | id = Coroutine $ \i -> (i, id) 176 | 177 | cof . cog = Coroutine $ \i -> 178 | let (x, cog') = runC cog i 179 | (y, cof') = runC cof x 180 | in (y, cof' . cog') 181 | ``` 182 | 183 | (We need to hide the default implementations of `id` and `.` from Prelude, since [`Control.Category`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Category.html) contains more generic implementations for them) 184 | 185 | As an example, let's define a coroutine which keeps an accumulating sum of the values it is fed. 186 | 187 | ```haskell 188 | accumSum :: Coroutine Integer Integer 189 | accumSum = Coroutine $ step 0 where 190 | step s i = (s+i, Coroutine $ step (s+i)) 191 | ``` 192 | 193 | Now we can compose `intsFrom` and `accumSum` using `.` 194 | 195 | ```haskell 196 | *Main> let sumFrom = accumSum . intsFrom 0 197 | *Main> evalList sumFrom [(),(),(),()] 198 | [0,1,3,6] 199 | ``` 200 | 201 | We can also generalize the idea of accumulation into a function called `scan` (analogous to [`Data.List.scanl`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-List.html#v:scanl)). 202 | 203 | ```haskell 204 | scan :: (a -> b -> a) -> a -> Coroutine b a 205 | scan f i = Coroutine $ step i where 206 | step a b = let a' = f a b in (a', scan f a') 207 | ``` 208 | 209 | Now `accumSum` can be defined as 210 | 211 | ```haskell 212 | accumSum = scan (+) 0 213 | ``` 214 | 215 | The [Arrow](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Arrow.html#t:Arrow) type-class extends Category in two ways. First, we get `arr` which is used to convert plain old functions into Arrows (i.e. Coroutines in our case). Second, we gain a set of new ways to compose coroutines that operate on pairs of values. 216 | 217 | The minimal definition for an Arrow instance requires the implementations for [`arr`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Arrow.html#v:arr) and [`first`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Arrow.html#v:first). 218 | 219 | ```haskell 220 | instance Arrow Coroutine where 221 | arr f = Coroutine $ \i -> (f i, arr f) 222 | 223 | first co = Coroutine $ \(a,b) -> 224 | let (c, co') = runC co a 225 | in ((c,b), first co') 226 | ``` 227 | 228 | The signature of `first` is 229 | 230 | ```haskell 231 | first :: Coroutine a b -> Coroutine (a, c) (b, c) 232 | ``` 233 | 234 | So it transforms a coroutine so that it can be applied to the first value of a tuple, while the second value stays unchanged. This might not seem too useful at first glance, but tuples in arrow computations can be thought of as multiple lines of computation running side-by-side, and `first` (and its pair, [`second`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Arrow.html#v:second)) enables us to apply different operations on each line. 235 | 236 | 237 | ## Practical Applications 238 | 239 | So what are these kind of coroutines good for? One interesting observation is that the arrow instance of coroutines can be thought of as a kind of stateful stream processor, where `Coroutine a b` takes in a stream of *a*'s and returns a stream of *b*'s, while potentially maintaining some internal state. These kind of stream processors are applicable for many things, one of which is [functional reactive programming][3]. So, in the next blog post, we'll implement a simple FRP-library using coroutines and arrows. 240 | 241 | 242 |
243 | Sami Hangaslammi <[sami.hangaslammi@leonidasoy.fi](mailto://sami.hangaslammi@leonidasoy.fi)> 244 | 245 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 246 | 247 | 248 | [1]: http://en.wikipedia.org/wiki/Stream_(computing) 249 | [2]: http://en.wikipedia.org/wiki/Coroutine 250 | [3]: http://en.wikipedia.org/wiki/Functional_reactive_programming 251 | -------------------------------------------------------------------------------- /2012/2012-01-13-implementing-semantic-anti-templating-with-jquery.md: -------------------------------------------------------------------------------- 1 | # Implementing Semantic Anti-Templating With jQuery 2 | 3 | [Single-page web applications][1] have been pretty much standard for quite a while, and I'm a strong advocate for 4 | numerous reasons (reduced latency, separation of concerns and ease of testing to name a few). 5 | 6 | However, one point I haven't felt too good about is client side rendering. It's ridiculous how cumbersome it is to 7 | compile the template, render the data and finally manipulate the DOM. For example, with popular template engines like 8 | [Handlebars][2] or [Mustache][3], you typically need do something like 9 | 10 | ``` 11 | 19 | ``` 20 | 21 | ```javascript 22 | var data = {title: "My New Post", body: "This is my first post!"} 23 | var source = $("#entry-template").html(); 24 | var template = Handlebars.compile(source); 25 | var html = template(data); 26 | $('container').empty().append(html); 27 | ``` 28 | 29 | Frustrated with the amount of labor, I decided to roll out my own and focus on simplicity. In this article, 30 | I walk through some of the main design decisions and corresponding implementation. For the impatient, here's 31 | [the demo site][4]. 32 | 33 | ## No syntax, please! 34 | 35 | I started with a modest goal: Given I have a static web page 36 | 37 | ```html 38 |
39 |
40 |
41 |
42 | ``` 43 | 44 | and a simple JavaScript object 45 | 46 | ```javascript 47 | data = { 48 | hello: "Hi there!" 49 | goodbye: "See ya!" 50 | }; 51 | ``` 52 | 53 | I want to render that on object on the page with a single function call. No template definition in script tags, 54 | no extra markup, no manual DOM manipulation. So, when I call `$('.container').render(data);`, I should see the 55 | following in the browser 56 | 57 | ```html 58 |
59 |
Hi there!
60 |
See ya!
61 |
62 | ``` 63 | 64 | We'll, it turned out, that wasn't too hard to implement. DOM manipulation is the bread and butter of jQuery, 65 | so all we need to do is 66 | 67 | 1. Iterate over the key-value pairs of the javascript objects 68 | 2. Render the value on the matching DOM element. 69 | 70 | The initial implementation looked like something like this (in CoffeeScript): 71 | 72 | ```coffeescript 73 | jQuery.fn.render = (data) -> 74 | template = this 75 | 76 | for key, value of data 77 | for node in template.find(".#{key}") 78 | node = jQuery(node) 79 | children = node.children().detach() 80 | node.text value 81 | node.append children 82 | ``` 83 | 84 | ## Getting rid of loops 85 | 86 | The next logical step was support for collections. I wanted to keep the interface exactly the same, without explicit 87 | loops or partials. Given an object like 88 | 89 | ```javascript 90 | friends = [ 91 | {name: "Al Pacino"}, 92 | {name: "The Joker"} 93 | ] 94 | ``` 95 | 96 | And a web page like 97 | 98 | ```html 99 |
    100 |
  • 101 |
102 | ``` 103 | 104 | When I call `$('.container').render(friends)`, I should see 105 | 106 | ```html 107 |
    108 |
  • Al Pacino
  • 109 |
  • The Joker
  • 110 |
111 | ``` 112 | 113 | Obviously, we need to extend the existing implementation with following steps 114 | 115 | 1. Iterate through the list of data objects 116 | 2. Take a new copy of the template for each object 117 | 3. Append the result to the DOM 118 | 119 | ```coffeescript 120 | jQuery.fn.render = (data) -> 121 | template = this.clone() 122 | context = this 123 | data = [data] unless jQuery.isArray(data) 124 | context.empty() 125 | 126 | for object in data 127 | tmp = template.clone() 128 | 129 | for key, value of data 130 | for node in tmp.find(".#{key}") 131 | node = jQuery(node) 132 | children = node.children().detach() 133 | node.text value 134 | node.append children 135 | 136 | context.append tmp.children() 137 | ``` 138 | 139 | It's worth noticing, that the rendering a single object is actually just an edge case of rendering a list of data 140 | objects. That gives us an opportunity to generalize the edge case by encapsulating the single object into a list as 141 | shown above. 142 | 143 | ## Do it again! 144 | 145 | The previous implementation works, kind of. However, if you call `$('container').render(friends)` twice, it fails. 146 | 147 | Result after the first call 148 | 149 | ```html 150 |
    151 |
  • Al Pacino
  • 152 |
  • The Joker
  • 153 |
154 | ``` 155 | 156 | Result after the second call 157 | 158 | ```html 159 |
    160 |
  • Al Pacino
  • 161 |
  • Al Pacino
  • 162 |
  • The Joker
  • 163 |
  • The Joker
  • 164 |
165 | ``` 166 | 167 | The reason is obvious. The current implementation finds two matching elements on the second call and renders 168 | the name on the both elements. That sucks, because it means you'd have to manually keep the original templates in safe. 169 | 170 | To avoid the problem, we need to 171 | 172 | 1. Cache the original template on the first `.render()` 173 | 2. Use the cached template on the successive calls 174 | 175 | Luckily, thanks to jQuery `data()`, the functionality is trivial to implement. 176 | 177 | ```coffeescript 178 | jQuery.fn.render = (data) -> 179 | context = this 180 | data = [data] unless jQuery.isArray(data) 181 | context.data('template', context.clone()) unless context.data 'template' 182 | context.empty() 183 | 184 | for object in data 185 | template = context.data('template').clone() 186 | 187 | # Render values 188 | for key, value of data 189 | for node in tmp.find(".#{key}") 190 | node = jQuery(node) 191 | children = node.children().detach() 192 | node.text value 193 | node.append children 194 | 195 | context.append template.children() 196 | ``` 197 | 198 | ## My way or the highway 199 | 200 | Rails has shown us how powerful it is to have strong conventions over configurations. Sometimes, however, you need to 201 | do the things differently and then it helps to have all the power. In JavaScript, that means functions. 202 | 203 | I wanted to be able to hook into rendering and define by functions how the rendering should happen. Common scenarios 204 | would include, e.g., decorators and attribute assignment. 205 | 206 | For example, given a template 207 | 208 | ```html 209 |
210 |
211 |
212 | ``` 213 | 214 | I want be able render the following data object with the directive 215 | 216 | ```coffeescript 217 | person = { 218 | firstname: "Lucy", 219 | lastname: "Lambda" 220 | } 221 | 222 | directives = 223 | name: -> "#{@firstname} #{@lastname}" 224 | 225 | $('.container').render person, directives 226 | ``` 227 | 228 | And the result should be 229 | 230 | ```html 231 |
232 |
Lucy Lambda
233 |
234 | ``` 235 | 236 | At first, implementing directives might seem like a daunting task, but given the flexibility and and power of 237 | javascript functions and object literals, it isn't that bad. We only need to 238 | 239 | 1. Iterate over the key-function pairs of the directive object 240 | 2. Bind the function to the data object and execute it 241 | 3. Assign the return value to the matching DOM element 242 | 243 | ```coffeescript 244 | jQuery.fn.render = (data, directives) -> 245 | context = this 246 | data = [data] unless jQuery.isArray(data) 247 | context.data('template', context.clone()) unless context.data('template') 248 | context.empty() 249 | 250 | for object in data 251 | template = context.data('template').clone() 252 | 253 | # Render values 254 | for key, value of data 255 | for node in tmp.find(".#{key}") 256 | renderNode node, value 257 | 258 | # Render directives 259 | for key, directive of directives 260 | for node in template.find(".#{key}") 261 | renderNode node, directive.call(object, node) 262 | 263 | context.append template.children() 264 | 265 | renderNode = (node, value) -> 266 | node = jQuery(node) 267 | children = node.children().detach() 268 | node.text value 269 | node.append children 270 | ``` 271 | 272 | ## Generalizing to nested data objects, lists and directives 273 | 274 | We'll, I bet you saw this coming. Why stop here, if we could easily support nested objects, lists and directives. 275 | For each child object, we should do exactly same operations that we did for the parent object. Sounds like recursion 276 | and, indeed, we need to add only couple of lines: 277 | 278 | ```coffeescript 279 | jQuery.fn.render = (data, directives) -> 280 | context = this 281 | data = [data] unless jQuery.isArray(data) 282 | context.data('template', context.clone()) unless context.data('template') 283 | context.empty() 284 | 285 | for object in data 286 | template = context.data('template').clone() 287 | 288 | # Render values 289 | for key, value of data when typeof value != 'object' 290 | for node in tmp.find(".#{key}") 291 | renderNode node, value 292 | 293 | # Render directives 294 | for key, directive of directives when typeof directive == 'function' 295 | for node in template.find(".#{key}") 296 | renderNode node, directive.call(object, node) 297 | 298 | # Render children 299 | for key, value of object when typeof value == 'object' 300 | template.find(".#{key}").render(value, directives[key]) 301 | 302 | context.append template.children() 303 | 304 | renderNode = (node, value) -> 305 | node = jQuery(node) 306 | children = node.children().detach() 307 | node.text value 308 | node.append children 309 | ``` 310 | 311 | ## Using Transparency in the real world applications 312 | 313 | Writing Transparency has been a delightful experience. It gave me a chance to get my feet wet with node.js, 314 | CoffeeScript, Jasmine and jQuery plugin development. At Leonidas, we've used it in a numerous projects in the past 315 | couple of months, and so far, we've been happy with it. 316 | 317 | The actual implementation is 66 lines of CoffeeScript, available at [GitHub][5]. If you want to give it a try, 318 | check [the demo site][4]. To use it in your own application, grab the 319 | [compiled and minified version](https://raw.github.com/leonidas/transparency/master/lib/jquery.transparency.min.js) 320 | and include it to your application with jQuery 321 | 322 | ```html 323 | 324 | 325 | ``` 326 | 327 | Discussions regarding the article are at [Reddit](http://www.reddit.com/search?q=Implementing+Semantic+Anti-Templating+With+jQuery). 328 | 329 | Cheers, 330 | 331 | Jarno Keskikangas <[jarno.keskikangas@leonidasoy.fi](mailto://jarno.keskikangas@leonidasoy.fi)> 332 | 333 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 334 | 335 | 336 | [1]: http://en.wikipedia.org/wiki/Single-page_application 337 | [2]: http://handlebarsjs.com/ 338 | [3]: http://mustache.github.com/ 339 | [4]: http://leonidas.github.com/transparency 340 | [5]: http://github.com/leonidas/transparency -------------------------------------------------------------------------------- /2012/2012-01-17-declarative-game-logic-afrp.md: -------------------------------------------------------------------------------- 1 | # Purely Functional, Declarative Game Logic Using Reactive Programming 2 | 3 | In the [previous article](https://github.com/leonidas/codeblog/blob/master/2012/2012-01-08-streams-coroutines.md) I introduced the `Coroutine` data type. In this second part I will show how coroutines can be used to implement a fixed time-step reactive programming library and use that library for modeling a simple game. The code examples will require a [basic proficiency in reading Haskell code](http://learnyouahaskell.com/). 4 | 5 | ## Classical FRP 6 | 7 | The classic model of functional reactive programming has two main concepts: 8 | 9 | * time varying values, which can be though of as functions `Time -> a` 10 | * events, which can be thought of as time-ordered (possible infinite) streams of `(Time, e)` pairs 11 | 12 | These can be used to model dynamic systems with continous time, but there are also many domains such as games and physics simulations which tend to use fixed time-steps instead, and these kind of systems can be modeled very conveniently using coroutines so that each call to the coroutine represents a single time-step. 13 | 14 | ## Fixed Time-Step FRP 15 | 16 | In fixed time-step FRP, coroutines are analogous to time varying values (or behaviors, as they are sometimes called). A coroutine of type `Coroutine a b` can be thought of as a time varying value of type `b` that is dependent on another time varying value of type `a`. 17 | 18 | So, for example, the position of a player character in a game can be thought of as `Position` that is dependent on `KeyboardInput`, so it would have the type 19 | 20 | ```haskell 21 | playerPosition :: Coroutine KeyboardInput Position 22 | ``` 23 | 24 | Events are simply time varying lists, where the list contains the events that occur during the current time-step. 25 | 26 | ```haskell 27 | type Event a = [a] 28 | ``` 29 | 30 | Since they are time varying values, events too depend on other time varying values. So for example 31 | 32 | ```haskell 33 | playerCollisions :: Coroutine Position (Event Collision) 34 | ``` 35 | 36 | The above type signature indicates that `Collision` events are emitted depending on the current player position. 37 | 38 | If a value is dependent on multiple other values, we use tuples. 39 | 40 | ```haskell 41 | pacmanCollisions :: Coroutine (PacPosition, [GhostPosition]) (Event Collision) 42 | ``` 43 | 44 | I.e. the collision events for [pac-man](http://en.wikipedia.org/wiki/Pac-Man) would depend on the position of pac-man and the positions of all ghosts. 45 | 46 | ## Connecting Dependent Values 47 | 48 | The `Arrow` instance we defined for coroutines in the previous article comes in handy for connecting time varying values with their dependencies. Instead of being functions of `Time -> a`, the time varying values in our fixed time-step system are analoguous to value streams, with one concrete value for every time step. Coroutines can then be seen as stream processors that take in a stream of dependencies and produce a stream of derived values. 49 | 50 | Using the above examples, you could for example pipe `playerPosition` and `playerCollision` together (since the collisions were dependent on the position) like this 51 | 52 | ``` 53 | playerPosition >>> playerCollisions 54 | ``` 55 | 56 | The above expression forms a new coroutine with the type `Coroutine KeyboardInput (Event Collision)`, where the keyboard state is first used to calculate the current player position, which is then used to generate collision events. 57 | 58 | I mentioned in the previous blog post that tuples in arrow operations can be thought as separate lines of computation. Thus, if we have a time varying tuple `(a, b)` and we want to pipe `a` and `b` into two different coroutines, we can do that using the operator [`***`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Arrow.html#v:-42--42--42-). If we want to pipe a single value `a` into two different coroutines, we can split it using the operator [`&&&`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Arrow.html#v:-38--38--38-). [This wiki page](http://en.wikibooks.org/wiki/Haskell/Understanding_arrows) is an excellent resource if you want a more detailed explanation (with illustrations) on how the different arrow operators work conceptually. 59 | 60 | ## Basic Combinators 61 | 62 | Let's extend the coroutine library with some simple event utilities that are useful for FRP. 63 | 64 | ```haskell 65 | -- | Map events into different kinds of events 66 | mapE :: (e -> e') -> Coroutine (Event e) (Event e') 67 | mapE = arr . map 68 | 69 | -- | Filter events based on a predicate function 70 | filterE :: (e -> Bool) -> Coroutine (Event e) (Event e) 71 | filterE = arr . filter 72 | 73 | -- | Replace every event occurence with a fixed event 74 | constE :: e -> Coroutine (Event e') (Event e) 75 | constE = mapE . const 76 | 77 | -- | Merge two time varying values using a combining function 78 | zipWithC :: (a -> b -> c) -> Coroutine (a, b) c 79 | zipWithC = arr . uncurry 80 | 81 | -- | Merge two event streams together 82 | zipE :: Coroutine (Event e, Event e) (Event e) 83 | zipE = zipWithC (++) 84 | ``` 85 | 86 | Another function that turns out to be very useful in practice is `scanE`, which is like the `scan` coroutine we introduced earlier, but for events. 87 | 88 | ```haskell 89 | scanE :: (a -> e -> a) -> a -> Coroutine (Event e) a 90 | scanE f i = Coroutine $ step i where 91 | step a e = let a' = foldl' f a e in (a', scanE f a') 92 | ``` 93 | 94 | `scanE` takes an initial value and a function that is used to combine incoming events with the value. The result is a value which can be changed by events, but otherwise stays constant. 95 | 96 | Other useful utilities for manipulating and combining time varying values are: 97 | 98 | ```haskell 99 | -- | Split a value into (current value, previous value) using the given 100 | -- initial value as the previous value during first call. 101 | withPrevious :: a -> Coroutine a (a, a) 102 | withPrevious first = Coroutine $ \i -> ((i, first), step i) where 103 | step old = Coroutine $ \i -> ((i, old), step i) 104 | 105 | -- | Delay the value by a single time-step, using the given initial value for 106 | -- the first call. 107 | delay :: a -> Coroutine a a 108 | delay a = withPrevious a >>> arr snd 109 | 110 | -- | Integrate a numerical value over time 111 | integrate :: Num a => a -> Coroutine a a 112 | integrate = scan (+) 113 | 114 | -- | Derivate a numerical value over time (i.e. return the delta between current 115 | -- and previous time-step. 116 | derivate :: Num a => Coroutine a a 117 | derivate = withPrevious 0 >>> zipWithC (-) 118 | 119 | -- | Trigger an event whenever the value satisfies the given predicate function 120 | watch :: (a -> Bool) -> Coroutine a (Event a) 121 | watch f = Coroutine $ \i -> 122 | if f i 123 | then ([i], watch f) 124 | else ([], watch f) 125 | ``` 126 | 127 | ## FRP Pong 128 | 129 | Using the utility functions defined above, let's try to define the rules of a simple Pong clone as a collection of coroutines. We'll begin by defining the necessary coroutines for the player to move his bat. 130 | 131 | ```haskell 132 | playerPos :: Coroutine Keyboard PlayerPos 133 | playerPos = playerSpeed >>> integrate startPos >>> arr (\y -> (10, y)) 134 | 135 | playerSpeed :: Coroutine Keyboard Int 136 | playerSpeed = arr keyboardDir where 137 | keyboardDir kb 138 | | isKeyDown kb up = -batSpeed 139 | | isKeyDown kb down = batSpeed 140 | | otherwise = 0 141 | ``` 142 | 143 | The types and constants used in the above coroutines are: 144 | 145 | ```haskell 146 | type Pos = (Int, Int) 147 | type PlayerPos = Pos 148 | 149 | batSpeed = 5 150 | batSize = (10,40) 151 | startPos = 200 152 | ``` 153 | 154 | The implementation of `playerPos` should be quite straightforward to follow. The player's y-position is calculated by integrating the player's speed and adding `startPos`. Notice how we don't store or manipulate state anywhere. We merely declare _how_ `playerPos` depends on the keyboard state. 155 | 156 | Modeling the ball is a more interesting problem. We'll start by declaring a few more helpful types and utility functions. 157 | 158 | ```haskell 159 | type BallPos = Pos 160 | type Velocity = (Int, Int) 161 | 162 | ballInitPos = (400,200) 163 | ballSize = (8,8) 164 | ballInitVel = (-6, -6) 165 | 166 | topWall = 10 167 | bottomWall = 590 168 | 169 | -- Ball bounce events for horizontal and vertical bounce 170 | data BallBounce = HBounce | VBounce 171 | 172 | -- Multiply a vector by a scalar 173 | vecMul :: Int -> (Int, Int) -> (Int, Int) 174 | vecMul c (x,y) = (x*c,y*c) 175 | 176 | -- Add two vectors 177 | vecAdd :: (Int, Int) -> (Int, Int) -> (Int, Int) 178 | vecAdd (a,b) (c,d) = (a+c,b+d) 179 | 180 | -- Adjust velocity based on a bounce event 181 | bounce :: Velocity -> BallBounce -> Velocity 182 | bounce (dx,dy) b = case b of 183 | HBounce -> (-dx,dy) 184 | VBounce -> (dx,-dy) 185 | ``` 186 | 187 | Now we can define the ball position in terms of bounce events: 188 | 189 | ```haskell 190 | ballPos :: Coroutine (Event BallBounce) BallPos 191 | ballPos = scanE bounce ballInitVel >>> scan vecAdd ballInitPos 192 | ``` 193 | 194 | We process the bounce events using the `bounce` function we defined above to calculate the current ball velocity, which is then used to calculate the ball position using a cumulative vector sum. 195 | 196 | 197 | Let's see how we can generate the bounce events. 198 | 199 | ```haskell 200 | wallBounce :: Coroutine BallPos (Event BallBounce) 201 | wallBounce = watch (\(_,y) -> y < topWall || y > bottomWall) >>> constE VBounce 202 | 203 | batBounce :: Coroutine (PlayerPos, BallPos) (Event BallBounce) 204 | batBounce = watch collision >>> constE HBounce 205 | 206 | collision :: (PlayerPos, BallPos) -> Bool 207 | collision ((px,py),(bx,by)) = abs (px-bx) < w' && abs (py-by) < h' where 208 | w' = (bw + pw) `div` 2 209 | h' = (bh + ph) `div` 2 210 | (bw,bh) = ballSize 211 | (pw,ph) = batSize 212 | 213 | ``` 214 | 215 | Here we are starting to see a problem. The ball position depends on bounce events which are generated from collisions with the top and bottom walls as wells as the player bat. However, in order to generate those collisions we need to know the ball position. Chicken and egg. 216 | 217 | So, what do we do? Let's assume for a moment, that we could somehow know the ball position before we generate it and write ballPos like this: 218 | 219 | ```haskell 220 | ballPos :: Coroutine (PlayerPos, BallPos) BallPos 221 | ballPos = arr (\(ppos, bpos) -> ((ppos, bpos), bpos)) 222 | >>> batBounce *** wallBounce 223 | >>> zipE 224 | >>> scanE bounce ballInitVel 225 | >>> scan vecAdd ballInitPos 226 | ``` 227 | 228 | Here we are perfectly able to formulate the dependencies of the ball position. As long as we already know the position, that is. 229 | 230 | Enter recursive arrows (aka black magic). 231 | 232 | ## Recursive Arrows 233 | 234 | In order to support arrow recursion, we need to define a new instance for our Coroutine. 235 | 236 | ```haskell 237 | instance ArrowLoop Coroutine where 238 | loop co = Coroutine $ \b -> 239 | let ((c,d),co') = runC co (b,d) 240 | in (c, loop co') 241 | ``` 242 | 243 | The signature of loop is 244 | 245 | ```haskell 246 | loop :: Coroutine (b,d) (c,d) -> Coroutine b c 247 | ``` 248 | 249 | What this means is that given a coroutine that takes in `(b,d)` tuples and outputs `(c,d)` tuples, we build a coroutine from *b* to *c*. So what happends to *d*? Let's illustrate with ascii art. 250 | 251 | ``` 252 | +-----------+ 253 | -- b --> | Coroutine | -- c --> 254 | +-> | (b,d)(c,d)| -+ 255 | | +-----------+ | 256 | | | 257 | +-------- d -------+ 258 | ``` 259 | 260 | So what `loop` does is it takes the output *d* and wraps it around back as an input. So the coroutine ends up receiving as input the value that it will itself produce *in the future*. 261 | 262 | This works only because of laziness, and you also have to be very careful about how you pipe your data so you don't create a paradox and destroy the universe. In our game, we avoid the paradox by piping out the previous value of the ball position, which can then be used to calculate the current position. 263 | 264 | Then we tie the ends together with `loop` and call it a day. 265 | 266 | ```haskell 267 | ballPos :: Coroutine PlayerPos BallPos 268 | ballPos = loop $ arr (\(ppos, bpos) -> ((ppos, bpos), bpos)) 269 | >>> batBounce *** wallBounce 270 | >>> zipE 271 | >>> scanE bounce ballInitVel 272 | >>> scan vecAdd ballInitPos 273 | >>> withPrevious ballInitPos 274 | ``` 275 | 276 | The magic happens at the last line, where we split the ball position into `(current pos, previous pos)` using `withPrevious`. During the first iteration, when no previous value exists, we use the `ballInitPos` as a placeholder. The previous position is then fed back into the couroutine by `loop`. 277 | 278 | ## Arrow Notation 279 | 280 | When you have several event streams all interacting with each other, it will become more difficult and cumbersome to express the game logic in terms of splitting and merging these streams using the arrow operators. Another option is to use the special [arrow notation](http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/arrow-notation.html) of GHC. The arrow notation must be enabled either with the compiler command line flag `-XArrows` or by adding the following line at the beginning of the source file. 281 | 282 | ```haskell 283 | {-# LANGUAGE Arrows #-} 284 | ``` 285 | 286 | For example, we could rewrite the original `playerPos` coroutine 287 | 288 | ```haskell 289 | playerPos :: Coroutine Keyboard PlayerPos 290 | playerPos = playerSpeed >>> integrate startPos >>> arr (\y -> (10, y)) 291 | ``` 292 | 293 | in arrow notation like this: 294 | 295 | ```haskell 296 | playerPos :: Coroutine Keyboard PlayerPos 297 | playerPos = proc kb -> do 298 | spd <- playerSpeed -< kb 299 | y <- integrate startPos -< spd 300 | returnA -< (10, y) 301 | ``` 302 | 303 | This notation is a bit more verbose, but it is a lot easier to see what is going on. We assign to "local variables" with the left arrow `<-` just like in monadic do-blocks, but arrows also require that you pipe in input from the other end. The mnemonic for the operators is that they form one long arrow going from right to left `<- -<` with the actual arrow operation in the middle. 304 | 305 | If we want to define recursive arrows using the arrow notation, we need to add the keyword `rec` to the recursive part. The `ballPos` coroutine could be written using the arrow notation like this: 306 | 307 | 308 | ```haskell 309 | ballPos :: Coroutine PlayerPos BallPos 310 | ballPos = proc plPos -> do 311 | rec batB <- batBounce -< (plPos, pos) 312 | wallB <- wallBounce -< pos 313 | vel <- scanE bounce ballInitVel <<< zipE -< (batB, wallB) 314 | pos <- delay ballInitPos <<< scan vecAdd ballInitPos -< vel 315 | 316 | returnA -< pos 317 | ``` 318 | 319 | Inside the rec-block, we can use a variable before we assign it (like we do with `pos` in the above example). And like before, we delay `pos` to its previous value so that it can actually be evaluated. 320 | 321 | ### Additional Arrow Syntax 322 | 323 | Since combining events from two sources (like `batB` and `wallB` above) is so common, we can define a new helper function that makes it a bit more convenient. It's also a good excuse to introduce another piece of arrow notation. 324 | 325 | ```haskell 326 | mergeE :: Coroutine i (Event e) -> Coroutine i (Event e) -> Coroutine i (Event e) 327 | mergeE = liftA2 (++) 328 | ``` 329 | 330 | Since `Coroutine` is an instance of `Applicative`, we can use [`liftA2`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Applicative.html#v:liftA2) to "lift" the standard list concatenation operator to work on two coroutines. 331 | 332 | Now it would be nice if we could just write something like `mergeE batBounce wallBounce`, but our `mergeE` function only works on coroutines that have the same input type. Luckily, when using arrow notation there is special syntax for these kind of functions and thus we can rewrite `ballPos` as: 333 | 334 | ```haskell 335 | ballPos :: Coroutine PlayerPos BallPos 336 | ballPos = proc plPos -> do 337 | rec bounces <- (| mergeE (batBounce -< (plPos, pos)) (wallBounce -< pos) |) 338 | vel <- scanE bounce ballInitVel -< bounces 339 | pos <- delay ballInitPos <<< scan vecAdd ballInitPos -< vel 340 | 341 | returnA -< pos 342 | ``` 343 | 344 | Inside the `(| |)`-brackets (sometimes called the "banana brackets"), we can call a function so that we pipe in different inputs for each parameter. For infix operators we don't even need the special brackets, so we could define an operator like 345 | 346 | ```haskell 347 | (<++>) :: Coroutine i (Event e) -> Coroutine i (Event e) -> Coroutine i (Event e) 348 | (<++>) = liftA2 (++) 349 | ``` 350 | 351 | and use it like this 352 | 353 | ```haskell 354 | ballPos :: Coroutine PlayerPos BallPos 355 | ballPos = proc plPos -> do 356 | rec bounces <- (batBounce -< (plPos, pos)) <++> (wallBounce -< pos) 357 | vel <- scanE bounce ballInitVel -< bounces 358 | pos <- delay ballInitPos <<< scan vecAdd ballInitPos -< vel 359 | 360 | returnA -< pos 361 | ``` 362 | 363 | 364 | ### Resetting the ball position 365 | 366 | Next we want to change the ball behavior so that when it goes out of the screen 367 | it is reset back to its initial position. We can generalize this kind of behaviour into a helper function that transforms a coroutine so that it will restart from the beginning when it receives an event. 368 | 369 | ```haskell 370 | restartWhen :: Coroutine a b -> Coroutine (a, Event e) b 371 | restartWhen co = Coroutine $ step co where 372 | step c (i, ev) = (o, Coroutine cont) where 373 | (o, c') = runC c i 374 | cont 375 | | null ev = step c' 376 | | otherwise = step co 377 | ``` 378 | 379 | We can then define the new resetting behaviour as another recursive arrow that uses the old `ballPos` behaviour. 380 | 381 | ```haskell 382 | resettingBallPos :: Coroutine PlayerPos BallPos 383 | resettingBallPos = proc plPos -> do 384 | rec pos <- restartWhen ballPos -< (plPos, reset) 385 | reset <- watch outOfBounds -< pos 386 | returnA -< pos 387 | where outOfBounds (x,_) = x < 0 || x > 800 388 | ``` 389 | 390 | or, alternatively, without using the arrow notation: 391 | 392 | ```haskell 393 | resettingBallPos :: Coroutine PlayerPos BallPos 394 | resettingBallPos = loop $ restartWhen ballPos >>> id &&& watch outOfBounds 395 | where outOfBounds (x,_) = x < 0 || x > 800 396 | ``` 397 | 398 | Now the ball resets back to its initial position whenever it flies out of the screen. 399 | 400 | ## Putting it All Together 401 | 402 | The main coroutine has the type `Coroutine Keyboard Rects`, i.e. every time it is called, it gets the current state of the keyboard as a parameter, and it returns a collection of rectangles that should be rendered on the screen. This allows our game logic to be a pure function which doesn't have to know anything about the library that is used for reading the keyboard and to do the actual graphics rendering. 403 | 404 | 405 | ```haskell 406 | game :: Coroutine Keyboard [Rect] 407 | game = proc kb -> do 408 | plPos <- playerPos -< kb 409 | blPos <- resettingBallPos -< plPos 410 | returnA -< [mkRect plPos batSize, mkRect blPos ballSize] 411 | 412 | mkRect :: Pos -> Size -> Rect 413 | mkRect (x,y) (w,h) = ((x-w',y-h'),(w,h)) where 414 | w' = w `div` 2 415 | h' = h `div` 2 416 | ``` 417 | 418 | We have now covered all the building blocks that are required for a simple game like pong (the complete code can be viewed [here](https://github.com/shangaslammi/frp-pong/blob/master/Pong/Game.hs)). Usually, most required behaviours can be defined using high level arrows and combinators, but sometimes you might want to drop down to a lower level, and code a game-specific coroutine, such as a state switcher. 419 | 420 | One important thing that we didn't cover yet is how to handle dynamic collections of game objects, where new objects with dynamic behaviour can be created mid-game and existing ones can disappear. These will be covered in the next article, along with a more complete example of game logic from a more complex game. 421 | 422 |
423 | 424 | Sami Hangaslammi <[sami.hangaslammi@leonidasoy.fi](mailto://sami.hangaslammi@leonidasoy.fi)> 425 | 426 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 427 | 428 | 429 | -------------------------------------------------------------------------------- /2012/2012-02-17-concatenative-haskell.md: -------------------------------------------------------------------------------- 1 | 2 | # Concatenative, Row-Polymorphic Programming in Haskell 3 | 4 | I've just read the article "[Why Concatenative Programming Matters](http://evincarofautumn.blogspot.com/2012/02/why-concatenative-programming-matters.html)", in which the author states the following: 5 | 6 | > In particular, there is no uniform way to compose functions of different numbers of arguments or results. To even get close to that in Haskell, you have to use the curry and uncurry functions to explicitly wrap things up into tuples. No matter what, you need different combinators to compose functions of different types, because Haskell doesn't’t have row polymorphism for function arguments, and it inherently can’t. 7 | 8 | This got me thinking about whether this sort of polymorphism is really impossible in Haskell or if there is some way to emulate it. In this blog post, I'll show one way to implement a concatenative DSL inside Haskell, which employs the same sort of genericity in function composition as the linked article. 9 | 10 | 11 | ## Heterogeneous Polymorphic Stacks 12 | 13 | The article highlights the problem that in Haskell point-free programming quickly becomes complicated when you start to compose functions of different arities or if you want to, for example, re-use a value multiple times in the expression. To side-step these problems, we are going to define our DSL so that all our functions operate on a stack (which is the traditional model for concatenative languages), so basically every function will have the signature 14 | 15 | ```haskell 16 | f :: s -> s' 17 | ``` 18 | 19 | Where the function `f` takes in a stack `s` and returns a modified stack `s'`. The input and output stacks need to have a different type, because we want to have strict, compile-time type-checking, so whenever a function pops a value out of a stack or pushes in a new value, the type of the stack changes. 20 | 21 | The stack needs to be heterogeneous, so the easiest way to model it in Haskell is to use a tuple. However, there are no generic functions to operate on n-arity tuples, so we will store the stack as nested pairs and use unit `()` to signify an empty stack. So, for example, if we have a stack which has an `Int` value on top, followed by a `String` value, the stack will be represented in Haskell like this: 22 | 23 | ```haskell 24 | exampleStack :: (((), String), Int) 25 | exampleStack = (((), "foobar"), 5) 26 | ``` 27 | 28 | Now we can implement fully polymorphic stack functions such as `push`, `dup` and `swap` very naturally. 29 | 30 | ```haskell 31 | push :: a -> s -> (s, a) 32 | push value stack = (stack, value) 33 | 34 | dup :: (stack, value) -> ((stack, value), value) 35 | dup (stack, value) = (((stack), value), value) 36 | 37 | swap :: ((s, a), b) -> ((s, b), a) 38 | swap ((s, a), b) = ((s, b), a) 39 | ``` 40 | 41 | See how the type signatures beautifully describe the stack operations (in the case of `swap` and `dup`, the type signature and implementation are basically the same). 42 | 43 | The generic parameter `s` here is the "rest of the stack" which can have any type and any number of elements. This is equal to the *∀A* parameter in the linked article. This achieves the same effect as "row polymorphism", because e.g. the `swap` function can take in any kind of stack `s` as long as it has at least two elements, `a` and `b`. 44 | 45 | This is how we implement a function that adds two numbers. 46 | 47 | ```haskell 48 | add :: Num n => ((s, n), n) -> (s, n) 49 | add ((s, a), b) = (s, a + b) 50 | ``` 51 | 52 | Again, the type system will statically guarantee that we cannot call `add` on an empty stack or a stack which only contains one element, or a stack which contains something other than two numbers at the top of the stack. But at the same time, we preserve full polymorphism since the parameter `s` is fully generic and its exact value is not examined inside the function. 53 | 54 | We can compose all these function using the normal function composition operator 55 | 56 | ```haskell 57 | test = add . push 2 . push 1 58 | ``` 59 | or we can use the `>>>` operator from `Control.Arrow` in order to have the operations in the order which they are executed 60 | 61 | ```haskell 62 | import Control.Arrow 63 | 64 | test = push 1 >>> push 2 >>> add 65 | ``` 66 | 67 | We can also create partially applied functions. 68 | 69 | ```haskell 70 | addTwo = push 2 >>> add 71 | ``` 72 | 73 | And we can check in GHCi that the inferred type makes sense 74 | 75 | ``` 76 | *Main> :t addTwo 77 | addTwo :: (s, Integer) -> (s, Integer) 78 | ``` 79 | 80 | As we can see, `addTwo` expects the stack to have one integer on the top of the stack and the same holds for the result (the original number is popped out of the stack, and the addition result is pushed back in). The function type signature also guarantees that the structure of the rest of the stack stays unchanged. 81 | 82 | 83 | ## Nicer Stack Notation 84 | 85 | Writing deeply nested tuples is impractical, so we can use a GHC extension called "type operators" to make the syntax a bit nicer. 86 | 87 | ```haskell 88 | {-# LANGUAGE TypeOperators #-} 89 | type s:.a = (s, a) 90 | 91 | infixl 1 :. 92 | ``` 93 | 94 | Now we can re-write the above function signatures like this: 95 | 96 | ```haskell 97 | push :: a -> s -> s:.a 98 | 99 | dup :: s:.a -> s:.a:.a 100 | 101 | swap :: s:.a:.b -> s:.b:.a 102 | 103 | exampleStack :: ():.String:.Int 104 | 105 | add :: Num n => s:.n:.n -> s:.n 106 | ``` 107 | 108 | Now it is much easier to see the structure of the stack from the type signatures, but we still need to use the clumsy nested tuples when building stacks, for example: 109 | 110 | ```haskell 111 | dup :: s:.a -> s:.a:.a 112 | dup (s,a) = ((s, a), a) 113 | ``` 114 | 115 | We can combine `TypeOperators` with infix data constructors to define a new type which allows us to use `:.` everywhere in types, patterns and expressions. 116 | 117 | ```haskell 118 | data s :. a = !s :. !a 119 | ``` 120 | 121 | This is semantically identical to a two-element, strict tuple, but it allows us to implement the above functions like this 122 | 123 | ```haskell 124 | push :: a -> s -> s:.a 125 | push a s = s:.a 126 | 127 | dup :: s:.a -> s:.a:.a 128 | dup (s:.a) = (s:.a:.a) 129 | 130 | swap :: s:.a:.b -> s:.b:.a 131 | swap (s:.a:.b) = s:.b:.a 132 | 133 | add :: P.Num n => s:.n:.n -> s:.n 134 | add (s:.a:.b) = s:.a + b 135 | ``` 136 | 137 | 138 | ## Function Lifting 139 | 140 | We cannot use "regular" Haskell functions directly with our stack, but we can define a few utility functions to make it easy to convert curried functions into functions that operate on the stack. 141 | 142 | 143 | ```haskell 144 | liftS :: (a -> b) -> (s:.a -> s:.b) 145 | liftS f (s:.a) = s:.f a 146 | 147 | liftS2 :: (a -> b -> c) -> (s:.a:.b -> s:.c) 148 | liftS2 f (s:.a:.b) = s:.f a b 149 | ``` 150 | 151 | We can also hide some of the default functions and operators from Prelude and define our own versions that are suitable for stack computations. 152 | 153 | ```haskell 154 | import Prelude hiding (Num(..), Eq(..), Ord(..), (/), null, (++)) 155 | import qualified Prelude as P 156 | 157 | (+) :: P.Num n => s:.n:.n -> s:.n 158 | (+) = liftS2 (P.+) 159 | 160 | (-) :: P.Num n => s:.n:.n -> s:.n 161 | (-) = liftS2 (P.-) 162 | 163 | (*) :: P.Num n => s:.n:.n -> s:.n 164 | (*) = liftS2 (P.*) 165 | 166 | (/) :: P.Fractional n => s:.n:.n -> s:.n 167 | (/) = liftS2 (P./) 168 | 169 | (<) :: P.Ord n => s:.n:.n -> s:.Bool 170 | (<) = liftS2 (P.<) 171 | 172 | (>) :: P.Ord n => s:.n:.n -> s:.Bool 173 | (>) = liftS2 (P.>) 174 | 175 | (>=) :: P.Ord n => s:.n:.n -> s:.Bool 176 | (>=) = liftS2 (P.>=) 177 | 178 | (<=) :: P.Ord n => s:.n:.n -> s:.Bool 179 | (<=) = liftS2 (P.<=) 180 | 181 | (==) :: P.Eq n => s:.n:.n -> s:.Bool 182 | (==) = liftS2 (P.==) 183 | 184 | 185 | -- List functions 186 | 187 | (++) :: s:.[a]:.[a] -> s:.[a] 188 | (++) = liftS2 (P.++) 189 | 190 | null :: s:.[a] -> s:.Bool 191 | null = liftS P.null 192 | 193 | decons :: s:.[a] -> s:.[a]:.a 194 | decons (s:.(x:xs)) = s:.xs:.x 195 | 196 | cons :: s:.[a]:.a -> s:.[a] 197 | cons (s:.xs:.x) = s:. x:xs 198 | ``` 199 | 200 | We can also define basic "shuffle" functions similar to what you can find in e.g. [Factor](http://factorcode.org/) to do primitive stack manipulation. 201 | 202 | ```haskell 203 | drop :: s:.a -> s 204 | drop (s:.a) = s 205 | 206 | nip :: s:.a:.b -> s:.b 207 | nip (s:.a:.b) = s:.b 208 | 209 | over :: s:.a:.b -> s:.a:.b:.a 210 | over (s:.a:.b) = (s:.a:.b:.a) 211 | 212 | pick :: s:.a:.b:.c -> s:.a:.b:.c:.a 213 | pick (s:.a:.b:.c) = (s:.a:.b:.c:.a) 214 | 215 | rotl :: s:.a:.b:.c -> s:.b:.c:.a 216 | rotl (s:.a:.b:.c) = s:.b:.c:.a 217 | 218 | rotr :: s:.a:.b:.c -> s:.c:.a:.b 219 | rotr (s:.a:.b:.c) = s:.c:.a:.b 220 | ``` 221 | 222 | It's nice to note here how the type signatures are practically equal to the implementations. 223 | 224 | 225 | ## Higher Order Functions 226 | 227 | It turns out that it's also easy to model higher order functions for this sort of structure, and again the signatures end up telling a lot about how the functions operate on the stack. The simplest possible higher-order function is `apply`, which executes a function stored in the stack. 228 | 229 | ```haskell 230 | apply :: s:.(s -> s') -> s' 231 | apply (s:.f) = f s 232 | ``` 233 | 234 | In order to make nicer looking quotations, we'll add `q` as a synonym for `push`. Now we can write functions using `apply` like this. 235 | 236 | ```haskell 237 | applyTest = push 2 >>> q( push 3 >>> (+) ) >>> apply 238 | ``` 239 | 240 | Another very commonly used combinator in stack based programming is `dip`, which executes a stack function under the top element of the stack and `dip2` which skips the top two elements. I.e. 241 | 242 | ```haskell 243 | dip :: s:.a:.(s -> s') -> s':.a 244 | dip (s:.a:.f) = f s :. a 245 | 246 | dip2 :: s:.a:.b:.(s -> s') -> s':.a:.b 247 | dip2 (s:.a:.b:.f) = f s :. a :. b 248 | ``` 249 | 250 | `keep` is a combinator which executes a stack function, but preserves the top element of the stack. 251 | 252 | ```haskell 253 | keep :: s:.a:.(s:.a -> s') -> s':.a 254 | keep (s:.a:.f) = f (s:.a) :. a 255 | ``` 256 | 257 | Let's then take a look at a basic if-then-else construct. 258 | 259 | ```haskell 260 | if_ :: s:.Bool:.(s -> s'):.(s -> s') -> s' 261 | ``` 262 | 263 | An if statement expects a boolean value, followed by two stack manipulation functions (these are equivalent to so called "quotations"). Here, once again, the strict typing conveys a wealth of information. The "then" and "else" blocks need to be able to operate on `s`, which is the state of the stack before the boolean value, and type system also ensures that both branches have to leave the stack to the same shape (`s'`), i.e. values can differ but the size of the stack and types of values must match. 264 | 265 | The implementation itself is straightforward. 266 | 267 | ```haskell 268 | if_ (s:.cond:.then_:.else_) 269 | | cond = then_ s 270 | | otherwise = else_ s 271 | ``` 272 | 273 | Next, let's see what a `map` function would look like 274 | 275 | ```haskell 276 | map :: s:.[a]:.(s:.a -> s:.b) -> s:.[b] 277 | ``` 278 | 279 | As we can see, `map` takes in a stack that contains a list `[a]` and a function that maps an `a` on top of the stack to `b`, and results in a stack with a new list `[b]` on top. The implementation is a bit trickier, since we need to carry the state of the stack `s` throughout the map. 280 | 281 | ```haskell 282 | map (s:.lst:.f) = (uncurry (:.)) (mapAccumL step s lst) where 283 | step s x = let s:.y = f (s:.x) in (s,y) 284 | ``` 285 | 286 | We also have enough building blocks already that we can implement recursive higher-order functions with just stack operations, without dropping back to "native" Haskell code. For example, `foldl`, `foldr` and `filter`. 287 | 288 | ```haskell 289 | foldr :: s:.[x]:.acc:.(s:.acc:.x -> s:.acc) -> s:.acc 290 | foldr = pick 291 | >>> null 292 | >>> q( drop >>> nip ) 293 | >>> q( q decons 294 | >>> dip2 295 | >>> rotl 296 | >>> q( q foldr >>> keep ) >>> dip 297 | >>> swap 298 | >>> apply ) 299 | >>> if_ 300 | 301 | 302 | foldl :: s:.[x]:.acc:.(s:.x:.acc -> s:.acc) -> s:.acc 303 | foldl = pick 304 | >>> null 305 | >>> q( drop >>> nip ) 306 | >>> q( q( decons >>> swap ) 307 | >>> dip2 308 | >>> rotl 309 | >>> q( q apply >>> keep ) 310 | >>> dip 311 | >>> rotr 312 | >>> foldl ) 313 | >>> if_ 314 | 315 | 316 | filter :: s:.[x]:.(s:.x -> s:.Bool) -> s:.[x] 317 | filter = swap >>> push [] >>> q step >>> foldr >>> nip where 318 | step = rotr 319 | >>> pick 320 | >>> q( q( apply 321 | >>> q( q cons ) 322 | >>> q( q drop ) 323 | >>> if_ ) >>> keep 324 | ) >>> dip2 325 | >>> q rotl >>> dip 326 | >>> swap 327 | >>> apply 328 | ``` 329 | 330 | There are probably simpler ways to implement the above functions using concatenative stack languages, but I don't have any real experience in programming with them, so this was the best I could come up with. 331 | 332 | It's worth mentioning that Haskell's type system was immensely helpful when piecing the more complex functions together. Although the error messages were pretty complex and difficult to read, the great thing is that any type error would contain both the actual and expected type of the stack (and the type of the stack of course contains the structure and type of all items in the stack), which was a great debugging tool. 333 | 334 | 335 | ## Side-Effectful Stack Programming 336 | 337 | In order to make any real programs, we need to implement a way to have side-effects like input and output in our stack programs. This requires a surprisingly small change. Instead of `(s -> s')`, the side-effectful stack functions have the type `Monad m => (s -> m s')`. We can keep all our existing functions as they are and gain a neat separation between pure and monadic stack operations. Monadic stack operations are chained using "Kleisli composition" (`>=>`) and pure stack operations need to end in `return` in order to be composable with monadic ones. 338 | 339 | Here are some simple stack IO functions 340 | 341 | ```haskell 342 | putStr :: s:.String -> IO s 343 | putStr (s:.x) = P.putStr x >> return s 344 | 345 | putStrLn :: s:.String -> IO s 346 | putStrLn (s:.x) = P.putStrLn x >> return s 347 | 348 | getLine :: s -> IO (s:.String) 349 | getLine s = P.getLine >>= \ln -> return (s:.ln) 350 | ``` 351 | 352 | Which we can use like this 353 | 354 | ```haskell 355 | hello = push "What's your name? " >>> return 356 | >=> putStr 357 | >=> push "Hello, " >>> return 358 | >=> getLine 359 | >=> (++) >>> push "!" >>> (++) >>> return 360 | >=> putStrLn 361 | ``` 362 | 363 | ## Conclusion 364 | 365 | While there aren't many practical uses for this kind of programming in Haskell, I still found it interesting how the concepts mapped onto the Haskell type system. But is this "real" row polymorphism or are there cases where this model is less generic than the one described in "Why Concatenative Programming Matters"? Let me know if I've missed something (via email or in [this Reddit thread](http://www.reddit.com/r/haskell/comments/ptji8/concatenative_rowpolymorphic_programming_in/)! 366 | 367 | 368 | All the code in this post can be found in [this gist](https://gist.github.com/1851086). 369 | 370 |
371 | Sami Hangaslammi <[sami.hangaslammi@leonidasoy.fi](mailto://sami.hangaslammi@leonidasoy.fi)> 372 | 373 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 374 | -------------------------------------------------------------------------------- /2012/2012-02-21-concatenative-haskell-ii-dsl.md: -------------------------------------------------------------------------------- 1 | # Concatenative Haskell Part II: Custom DSL Syntax Using QuasiQuotes 2 | 3 | In the [previous post](https://github.com/leonidas/codeblog/blob/master/2012/2012-02-17-concatenative-haskell.md) I introduced a way to emulate concatenative, stack based programming in Haskell code. The solution works, but it is a bit impractical to write 4 | 5 | ```haskell 6 | foo = push 1 >>> push 2 >>> (+) 7 | ``` 8 | 9 | instead of being able to simply write something like 10 | 11 | ```haskell 12 | foo = cc 1 2 (+) 13 | ``` 14 | 15 | 16 | I've been trying for the past day to implement something like `cc` using various typeclass and type level programming tricks, but while it's probably possible, I found my knowledge in this area lacking. Even though some solutions came close to kind-of-working like the above example, the implementations were very brittle and required lots of explicit type annotations to compile. 17 | 18 | 19 | So, I decided to tackle the problem in a completely different way using [Template Haskell](http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/template-haskell.html), so the above example becomes 20 | 21 | ```haskell 22 | foo = [cc| 1 2 (+) |] 23 | ``` 24 | 25 | Not quite as nice, but tolerable, and it'll be a good Template Haskell exercise. If you are completely new to Template Haskell, you can read my [`Basic Tutorial of Template Haskell`](https://github.com/leonidas/codeblog/blob/master/2011/2011-12-27-template-haskell.md) for a short introduction. 26 | 27 | 28 | ## Quasi-Quotes 29 | 30 | The syntax `[foo| ... |]` is called a [quasi-quote](http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/template-haskell.html#th-quasiquotation) where `foo` is a specific, named "quoter". The section between the pipe characters can contain any syntax that the quoter recognizes. 31 | 32 | From the implementor's point of view, to define a new quasi-quoter you basically just need to define a function that takes a string, parses it and produces Haskell [AST](http://en.wikipedia.org/wiki/Abstract_syntax_tree) using Template Haskell. 33 | 34 | The nice thing about quasi-quoting based internal DSLs (compared to external DSLs) is that since the DSL is translated into Haskell AST, we gain all the benefits of Haskell's static type system. This means that any syntax or type error we make using the DSL is caught at compile time. 35 | 36 | 37 | ## Stack Language Parsing 38 | 39 | We could implement our own custom parser, which would give us complete freedom to define any kind of syntax, but because 1) I'm pathologically lazy and 2) I've been looking for an excuse to do something with the [`haskell-src-meta`](http://hackage.haskell.org/package/haskell-src-meta) package, I'm going to define the custom postfix language syntax in terms of Haskell's syntax and use the Haskell parser from [`haskell-src-exts`](http://hackage.haskell.org/package/haskell-src-exts) package. 40 | 41 | The real work-horse in this entry will be the [`parseExp`](http://hackage.haskell.org/packages/archive/haskell-src-exts/1.11.1/doc/html/Language-Haskell-Exts-Parser.html) function, which parses a string containg a Haskell expression and returns the syntax tree. The `haskell-src-meta` package is used to convert the `haskell-src` package's syntax tree to a format usable with Template Haskell. 42 | 43 | 44 | ## Test-Driven Development 45 | 46 | This time, I will proceed in test-driven style and specify the syntax of the DSL incrementally via test cases using [`HUnit`](http://hackage.haskell.org/package/HUnit) and [`hspec`](http://hackage.haskell.org/package/hspec). 47 | 48 | Here's the basic structure for the test module. 49 | 50 | ```haskell 51 | {-# LANGUAGE TemplateHaskell, QuasiQuotes, TypeOperators #-} 52 | 53 | import Test.HUnit 54 | import Test.Hspec 55 | import Test.Hspec.HUnit 56 | 57 | import Prelude hiding (drop, foldl, null) 58 | 59 | import Language.Concat 60 | 61 | specs = describe "Concatenative DSL" [] 62 | 63 | main = hspec specs 64 | ``` 65 | 66 | The `Language.Concat` module is a cleaned up version of the code from the previous entry, which exports the stack data type `s :. a` and the basic stack functions. You can browse the module contents [here](https://github.com/shangaslammi/concat-dsl-qq/blob/master/Language/Concat/Stack.hs). 67 | 68 | As the first, simplest possible test case, let's add a test for an empty concatenative program, which should result in a Haskell function that takes a stack and returns it unchanged. 69 | 70 | ```haskell 71 | specs = describe "Concatenative DSL" $ 72 | [ it "should treat an empty program as the stack identity function" $ do 73 | let prog :: s -> s 74 | prog = [cc| |] 75 | prog () @?= () 76 | prog (():.1) @?= () :. 1 77 | ] 78 | ``` 79 | 80 | The [`@?=`](http://hackage.haskell.org/packages/archive/HUnit/latest/doc/html/Test-HUnit-Base.html#v:-64--63--61-) operator is the equality assertion operator from HUnit, whereas `:.` is the stack building operator from the [previous post](https://github.com/leonidas/codeblog/blob/master/2012/2012-02-17-concatenative-haskell.md). 81 | 82 | The `cc` quasi-quotation evaluates to a Haskell function that takes in a stack and returns a (potentially) modified stack, and we test the function with an empty and non-empty stacks. 83 | 84 | 85 | ## Quasi-Quoter Implementation 86 | 87 | The scaffolding for our quoter looks like this 88 | 89 | ```haskell 90 | {-# LANGUAGE TemplateHaskell #-} 91 | 92 | module Language.Concat.TH (cc) where 93 | 94 | import Language.Haskell.TH 95 | import Language.Haskell.TH.Quote 96 | 97 | cc = QuasiQuoter 98 | { quoteExp = parseCC 99 | , quotePat = undefined 100 | , quoteType = undefined 101 | , quoteDec = undefined 102 | } 103 | 104 | parseCC :: String -> Q Exp 105 | parseCC = undefined 106 | ``` 107 | 108 | The `cc` quoter can only be spliced into an expression context, so we set the `quoteExp` field and leave the rest undefined. 109 | 110 | In order to implement the functionality described in the first test-case, we'll simply test whether the input string is empty after stripping out all whitespace and if so, return a [`VarE`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Syntax.html#v:VarE) (variable expression) that refers to the identity function. 111 | 112 | ```haskell 113 | {-# LANGUAGE ViewPatterns #-} 114 | 115 | import Data.Char (isSpace) 116 | 117 | parseCC :: String -> Q Exp 118 | parseCC (stripSpace -> "") = return $ VarE 'id -- ' (workaround for github's syntax highlight issue) 119 | 120 | stripSpace :: String -> String 121 | stripSpace = filter (not.isSpace) 122 | ``` 123 | 124 | The arrow syntax in the pattern of parseCC is part of the [View Patterns](http://hackage.haskell.org/trac/ghc/wiki/ViewPatterns) extension. The single-quote prefix in `'id` (which github's syntax highlight unfortunately trips on) is used for translating identifiers in the current scope into fully qualified name nodes in Template Haskell AST. 125 | 126 | 127 | ## Literal Values 128 | 129 | The next thing we'll implement is the handling of literal values, starting again from the simplest case. 130 | 131 | ```haskell 132 | it "should implicitly push a lone literal value into the stack" $ do 133 | let prog = [cc| 1 |] 134 | prog () @?= ():.1 135 | prog (():."foo") @?= () :. "foo" :. 1 136 | ``` 137 | 138 | Let's test in GHCi what the `parseExp` function from `haskell-src-exts` returns for the string in question. 139 | 140 | ```haskell 141 | > parseExp " 1 " 142 | ParseOk (Lit (Int 1)) 143 | ``` 144 | 145 | Now we know what to pattern-match against: 146 | 147 | ```haskell 148 | import Language.Haskell.Exts.Parser 149 | import qualified Language.Haskell.Exts.Syntax as S 150 | import qualified Language.Haskell.Meta as M 151 | 152 | parseCC :: String -> Q Exp 153 | parseCC (stripSpace -> "") = return $ VarE 'id -- ' 154 | parseCC (parseExp -> ParseOk (S.Lit lit)) = 155 | return $ AppE (VarE 'Stack.push) $ LitE $ M.toLit lit 156 | ``` 157 | 158 | [`AppE`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Syntax.html#v:AppE) (apply expression) applies a function to a value, in this case the `Stack.push` function to the literal value. 159 | 160 | [`LitE`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Syntax.html#v:LitE) is a literal expression and [`toLit`](http://hackage.haskell.org/packages/archive/haskell-src-meta/0.5.1/doc/html/Language-Haskell-Meta-Syntax-Translate.html#v:toLit) from the `haskell-src-meta` package converts the literal node from the Haskell parser to a literal node in the Template Haskell AST. 161 | 162 | ### Multiple Literals 163 | 164 | What about more than one literal value? 165 | 166 | ```haskell 167 | it "should push consecutive literals into the stack" $ do 168 | let prog = [cc| 1 "foo" 3 |] 169 | prog () @?= ():.1:."foo":.3 170 | ``` 171 | 172 | Perhaps surprisingly, the string `1 "foo" 3` is syntactically valid Haskell. Even though it wouldn't type-check in a real program, the parser will happily produce a syntax tree for us. 173 | 174 | ```haskell 175 | > parseExp "1 \"foo\" 3" 176 | ParseOk (App (App (Lit (Int 1)) (Lit (String "foo"))) (Lit (Int 3))) 177 | ``` 178 | 179 | What it means is that first we apply the function `1` to the value `"foo"` and then apply the resulting function to `3`. Of course integers aren't functions so the expression wouldn't compile, but at the syntax level, everything is fine. 180 | 181 | As the syntax trees get more complex, it's time to rethink the structure our implementation a bit. Since chains of operations on the stack are expressed as nested function applications, we should have a recursive function that processes the syntax tree and produces a list of expressions where each element represents a "word" (in [Factor](http://factorcode.org/) terminology). A second function will take a list of words and fold them together using the arrow operator [`>>>`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Category.html#v:-62--62--62-). 182 | 183 | ```haskell 184 | import Control.Arrow ((>>>)) 185 | import Data.List (foldl1') 186 | 187 | parseCC :: String -> Q Exp 188 | parseCC (stripSpace -> "") = return $ VarE 'id -- ' 189 | parseCC (parseExp -> ParseOk exp) = return . combineExps . extractWords $ exp 190 | 191 | extractWords :: S.Exp -> [Exp] 192 | extractWords exp = case exp of 193 | S.Lit lit -> [push $ M.toExp $ M.toLit lit] 194 | S.App f v -> extractWords f ++ extractWords v 195 | 196 | combineExps :: [Exp] -> Exp 197 | combineExps = foldl1' step where 198 | step r l = InfixE (Just r) arr (Just l) 199 | arr = VarE '(>>>) -- ' 200 | 201 | push :: Exp -> Exp 202 | push = AppE $ VarE 'Stack.push 203 | ``` 204 | 205 | As planned, `extractWords` takes a syntax tree and produces a list of (Template Haskell) expressions. It currently handles literals and function application, but we'll expand the case statement as we add new features. 206 | 207 | `combineExps` takes the list of expressions and folds them together by creating a tree of [`InfixE`](http://hackage.haskell.org/packages/archive/template-haskell/latest/doc/html/Language-Haskell-TH-Syntax.html#v:InfixE) (infix expression) nodes, so that `[expA, expB, expC]` becomes `expA >>> expB >>> expC`. 208 | 209 | 210 | ## Function Words 211 | 212 | After literals, it's time to tackle stack functions such as `dup`, so let's add another test case. 213 | 214 | ```haskell 215 | it "should apply named stack functions to the current stack" $ do 216 | let prog = [cc| 1 dup |] 217 | prog () @?= () :. 1 :. 1 218 | ``` 219 | 220 | It turns out this is a trivial addition to our current `extractWords` function. 221 | 222 | ```haskell 223 | extractWords :: S.Exp -> [Exp] 224 | extractWords exp = case exp of 225 | S.Lit lit -> [push $ M.toExp $ M.toLit lit] 226 | S.App a p -> extractWords a ++ extractWords p 227 | var@(S.Var _) -> [M.toExp var] 228 | ``` 229 | 230 | We'll assume that in the context of the DSL, all variables refer to stack functions, so we'll just return the variable as-is. So for example, in our test-case, `[cc| 1 dup |]` is transformed into the equivivalent of `push 1 >>> dup`. 231 | 232 | 233 | ## Infix Operators 234 | 235 | Since all infix operators take two parameters, we can make it so that the quoter takes care of "lifting" for us. This means that instead of creating our own lifted operators like in the previous blog post (`(+) = liftS2 (Prelude.+)`), we can just use any regular infix operator. The test case looks like this 236 | 237 | ```haskell 238 | it "applies infix operators to the top two elements of the stack" $ do 239 | let prog = [cc| 1 2 (+) |] 240 | prog () @?= () :. 3 241 | ``` 242 | 243 | Again, we can use GHCi to examine the parse tree for our test case 244 | 245 | ```haskell 246 | > parseExp "1 2 (+)" 247 | ParseOk (App (App (Lit (Int 1)) (Lit (Int 2))) (Var (UnQual (Symbol "+")))) 248 | ``` 249 | 250 | It would be nice if we could drop the brackets, but `"1 2 +"` would be a syntax error in Haskell. I first thought about wrapping the whole expression in brackets, because "(1 2 +)" _would_ be syntactically valid, but the same trick wouldn't work for programs such as "(1 2 3 + +)", so let's just live with the bracketed operators for now. 251 | 252 | ```haskell 253 | extractWords :: S.Exp -> [Exp] 254 | extractWords exp = case exp of 255 | S.Lit lit -> [push $ M.toExp $ M.toLit lit] 256 | S.App a p -> extractWords a ++ extractWords p 257 | var@(S.Var (S.UnQual (S.Symbol _))) -> [liftS2 (M.toExp var)] 258 | var@(S.Var _) -> [M.toExp var] 259 | 260 | liftS2 :: Exp -> Exp 261 | liftS2 = AppE $ VarE 'Stack.liftS2 -- ' 262 | ``` 263 | 264 | The implementation is almost the same as for function words in the previous step. We just apply `liftS2` to the given symbol to turn a regular infix operator into a stack operator. 265 | 266 | 267 | ## Quotations 268 | 269 | Quotations (again, in Factor terminology, not be confused with quasi-quotations) are code blocks that are "quoted" (i.e. not executed immediately) and stored in the stack. In Factor's syntax quotations are enclosed in square brackets and we'll borrow that syntax for our DSL as well. 270 | 271 | ```haskell 272 | , it "should push operations in square brackets to the stack without executing them" $ do 273 | let prog = [cc| 1 [2 (+)] call |] 274 | prog () @?= () :. 3 275 | ``` 276 | 277 | Surprisingly, list values are not categorized as literals in the syntax tree, but have their own node type. 278 | 279 | ```haskell 280 | > parseExp "[2 (+)]" 281 | ParseOk (List [App (Lit (Int 2)) (Var (UnQual (Symbol "+")))]) 282 | ``` 283 | 284 | Again, the implementation is just a matter of adding a new pattern to our case expression in `extractWords`. 285 | 286 | ```haskell 287 | extractWords :: S.Exp -> [Exp] 288 | extractWords exp = case exp of 289 | S.Lit lit -> [push $ M.toExp $ M.toLit lit] 290 | S.App a p -> extractWords a ++ extractWords p 291 | var@(S.Var (S.UnQual (S.Symbol _))) -> [liftS2 (M.toExp var)] 292 | var@(S.Var _) -> [M.toExp var] 293 | S.List q -> return $ push $ extractQuot q 294 | 295 | extractQuot :: [S.Exp] -> Exp 296 | extractQuot [] = VarE 'id -- ' 297 | extractQuot [e] = combineExps $ extractWords e 298 | ``` 299 | 300 | An empty list means a quotation that does nothing (i.e. the stack identity function) and a single element list is recursively processed with `extractWords` and combined into a single expression that can be pushed to the stack. 301 | 302 | Now we have enough functionality that we can rewrite the `foldl` example from the previous blog post using the new syntax. 303 | 304 | ```haskell 305 | foldl = [cc| 306 | pick null 307 | [drop nip] 308 | [ [decons swap] dip2 rotl 309 | [[call] keep] dip rotr foldl 310 | ] if_ 311 | |] 312 | ``` 313 | 314 | 315 | ## List Building 316 | 317 | There's one problem, though. Since we used the square brackets syntax for quotations, we are left with no way to actually build lists in our DSL. We'll solve this by adding a new stack function that lets us turn a quotation into a list. 318 | 319 | ```haskell 320 | it "should turn quotations into lists with the 'list' word" $ do 321 | let prog = [cc| [1 2 dup] list |] 322 | prog () @?= () :. [1, 2, 2] 323 | ``` 324 | 325 | This functionality isn't really related to our DSL and requires no changes to the parser. We just need to implement a new stack function, `list`, which executes a quotation in an empty stack and then folds each item in the resulting stack into a list. 326 | 327 | ```haskell 328 | {-# LANGUAGE FunctionalDependencies #-} 329 | {-# LANGUAGE FlexibleInstances #-} 330 | {-# LANGUAGE FlexibleContexts #-} 331 | {-# LANGUAGE UndecidableInstances #-} 332 | 333 | list :: BuildList s' a => s :. (() -> s') -> s :. [a] 334 | list (s:.q) = s :. (P.reverse $ buildList (q ())) 335 | 336 | class BuildList s a | s -> a where 337 | buildList :: s -> [a] 338 | 339 | instance BuildList () a where 340 | buildList () = [] 341 | 342 | instance BuildList s a => BuildList (s:.a) a where 343 | buildList (s:.a) = a : buildList s 344 | ``` 345 | 346 | The implementation of `list` goes slightly deeper into typeclass territory. With the `BuildList s a` class we define that for some type `s` we can build a list of type `[a]`, where the element type `a` depends on `s`. Then we just define typeclass instances so that the empty stack `()` always returns an empty list, and any list-buildable stack with a single element on top builds into a list with that element as head. 347 | 348 | Now we can create lists to test the `foldl` function we defined earlier. 349 | 350 | ```haskell 351 | > [cc| [1 2 3 4 5] list 0 [(+)] foldl |] () 352 | () :. 15 353 | ``` 354 | 355 | 356 | ## Conclusion 357 | 358 | Hopefully this post has given you some ideas on how to utilize `haskell-src-exts` and `haskell-src-meta` to create DSLs that extend or mutate the base Haskell syntax. If you have any comments or questions, please feel free to message me via github's messaging system or [email](mailto://sami.hangaslammi@leonidasoy.fi). 359 | 360 | 361 | You can browse the code in [this github repo](https://github.com/shangaslammi/concat-dsl-qq). 362 | 363 | 364 | You can also discuss this article on [Reddit](http://www.reddit.com/r/haskell/comments/pzh53/concatenative_haskell_part_ii_custom_dsl_syntax/). 365 | 366 | 367 |
368 | Sami Hangaslammi <[sami.hangaslammi@leonidasoy.fi](mailto://sami.hangaslammi@leonidasoy.fi)> 369 | 370 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 371 | -------------------------------------------------------------------------------- /2013/2013-01-14-observable-sharing.md: -------------------------------------------------------------------------------- 1 | 2 | # Observable Sharing Using Data.Reify 3 | 4 | When I started learning about functional programming after years of writing object oriented code, one difference that stood out for me is how, unlike many functional languages, object oriented languages have this built-in notion of identity for objects separate from object equality. 5 | 6 | Let's compare these two (contrived) examples for defining persons. First in Python and then in Haskell. 7 | 8 | ```python 9 | class Person: 10 | def __init__(self, name, children): 11 | self.name = name 12 | self.children = children 13 | 14 | bob = Person("Bob", []) 15 | ``` 16 | 17 | ```haskell 18 | data Person = Person 19 | { name :: String 20 | , children :: Person 21 | } 22 | 23 | bob = Person "Bob" [] 24 | ``` 25 | 26 | Now in Python, if we were to define another person that is also called "Bob", we could determine that we are dealing with a different Bob using the `is` operator. 27 | 28 | ```python 29 | bob = Person("Bob", []) 30 | bob2 = Person("Bob", []) 31 | 32 | assert bob is not bob2 33 | ``` 34 | 35 | In Haskell, though, if we define 36 | 37 | ```haskell 38 | bob = Person "Bob" [] 39 | bob2 = Person "Bob" [] 40 | ``` 41 | 42 | we don't have any built in way to determine whether `bob` is the same person as `bob2` and actually, since the data is immutable, some compiler might, in theory, very well use common subexpression elimination to optimize the above to: 43 | 44 | ```haskell 45 | bob = Person "Bob" [] 46 | bob2 = bob 47 | ``` 48 | 49 | Of course, when dealing with immutable data it shouldn't matter at all whether two variables actually point to the exact same data in memory or not, but there are some cases where we want to know whether two data structures actually share data or if they merely have an equal value. For example 50 | 51 | ```haskell 52 | mary = Person "Mary" [] 53 | bob = Person "Bob" [mary] 54 | alice = Person "Alice" [mary] 55 | ``` 56 | 57 | The way we current have defined `Person` we have no way of knowing wether Mary is the daughter of both Bob and Alice or whether both just happen to have a child with the same name. In Haskell, if we care about identity, we have to provide it manually. 58 | 59 | ```haskell 60 | import Data.Unique 61 | import Data.Function (on) 62 | 63 | data UniquePerson = UniquePerson 64 | { name :: String 65 | , children :: [UniquePerson] 66 | , identity :: Unique 67 | } 68 | 69 | is :: UniquePerson -> UniquePerson -> Bool 70 | is = (==) `on` identity 71 | ``` 72 | 73 | However, this comes with the limitation that we can only "instantiate" new persons in the IO monad, which makes sense as a unique identity is actually an observable side-effect. 74 | 75 | ```haskell 76 | import Control.Applicative ((<$>)) 77 | 78 | main = do 79 | mary <- UniquePerson "Mary" [] <$> newUnique 80 | bob <- UniquePerson "Bob" [mary] <$> newUnique 81 | alice <- UniquePerson "Alice" [mary] <$> newUnique 82 | 83 | print $ (children bob !! 0) `is` (children alice !! 0) 84 | ``` 85 | 86 | 87 | There's one problem with having to initialize person data in the IO monad, namely that we are now dependent on the order of initialization. This will cause us trouble if change the data type from a parent-child hierarchy to something that can have circular links. 88 | 89 | ```haskell 90 | data UniquePerson = UniquePerson 91 | { name :: String 92 | , friends :: [UniquePerson] 93 | , identity :: Unique 94 | } 95 | 96 | main = do 97 | bob <- UniquePerson "Bob" [] <$> newUnique 98 | fred <- UniquePerson "Fred" [bob] <$> newUnique 99 | ``` 100 | 101 | Now Fred can be a friend of Bob or Bob can be the friend of Fred, but there's no immediately obvious way to model the relationship both ways. We could change the data type to only refer to the friend using his ID, as in: 102 | 103 | 104 | ```haskell 105 | data UniquePerson = UniquePerson 106 | { name :: String 107 | , friends :: [Unique] 108 | , identity :: Unique 109 | } 110 | 111 | main = do 112 | bobId <- newUnique 113 | fredId <- newUnique 114 | 115 | bob = UniquePerson "Bob" [fredId] bobId 116 | fred = UniquePerson "Fred" [bobId] fredId 117 | ``` 118 | 119 | But then we'd have to keep a lookup map of ID->Person mappings and dereference the id's through that whenever we want to operate on the data and where's the fun in that? 120 | 121 | 122 | It's worth noting, that for non-unique persons we don't have the same problem. 123 | 124 | ```haskell 125 | data Person = Person 126 | { name :: String 127 | , friends :: [Person] 128 | } 129 | 130 | bob = Person "Bob" [fred] 131 | fred = Person "Fred" [bob] 132 | ``` 133 | 134 | As pure expressions aren't necessary evaluated in order, the order of declarations doesn't matter and we can refer to a variable above its actual declaration. 135 | 136 | Wouldn't it be nice if we could somehow use the pure data type to declare relationships between the persons, but still attach each person with a unique identity? This is where the [`data-reify`](http://hackage.haskell.org/package/data-reify) package comes in handy. 137 | 138 | `data-reify` is based on the research paper [Type-Safe Observable Sharing in Haskell](http://www.cs.uu.nl/wiki/pub/Afp/CourseLiterature/Gill-09-TypeSafeReification.pdf) and it uses [GHC-specific tricks](http://hackage.haskell.org/packages/archive/base/latest/doc/html/System-Mem-StableName.html) to identify shared nodes in a data structure, essentially giving us the uniqueness property for free. 139 | 140 | To use `data-reify` you need to have a recursive data type (such as our `Person` type) and a mirror type where the points of recursion are replaced by abstract references. 141 | 142 | ```haskell 143 | data Person = Person String [Person] 144 | data Person' ref = Person' String [ref] 145 | ``` 146 | 147 | Now we can derive a [`MuRef`](http://hackage.haskell.org/packages/archive/data-reify/latest/doc/html/Data-Reify.html#t:MuRef) instance that maps from `Person` to `Person'`. 148 | 149 | ```haskell 150 | {-# LANGUAGE TypeFamilies #-} 151 | 152 | import Data.Reify 153 | import Data.Traversable (traverse) 154 | 155 | instance MuRef Person where 156 | type DeRef Person = Person' 157 | 158 | mapDeRef f (Person name friends) = 159 | Person' name <$> traverse f friends 160 | ``` 161 | 162 | The type of [`mapDeRef`](http://hackage.haskell.org/packages/archive/data-reify/latest/doc/html/Data-Reify.html#v:mapDeRef) is a bit cryptic, but the gist of it is that it gets as a parameter a function `f` and a value of the original data type (`Person`) and the implementation has to return a value of the mirror type (`Person'`) where each recursive field is mapped through `f`. 163 | 164 | Now that we have a `MuRef` instance, we can use the [`reifyGraph`](http://hackage.haskell.org/packages/archive/data-reify/latest/doc/html/Data-Reify.html#v:reifyGraph) function to build a list of `(ID, Person')` pairs and then initialize a `UniquePerson` based on that. 165 | 166 | ```haskell 167 | makeUnique :: Person -> IO UniquePerson 168 | makeUnique p = do 169 | Graph nodes rootId <- reifyGraph p 170 | 171 | let deref identity = UniquePerson name uniqueFriends identity where 172 | uniqueFriends = map deref friends 173 | Person' name friends = fromJust $ lookup identity nodes 174 | 175 | return $ deref rootId 176 | ``` 177 | 178 | Note that this uses the [`Unique`](http://hackage.haskell.org/packages/archive/data-reify/latest/doc/html/Data-Reify-Graph.html#t:Unique) type from [`Data.Reify.Graph`](http://hackage.haskell.org/packages/archive/data-reify/latest/doc/html/Data-Reify-Graph.html) which is different from [`Data.Unique`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Unique.html), but with small changes to `makeUnique` we can, again, use `Data.Unique.Unique` to ensure the uniqueness of the identities throughout our program. 179 | 180 | ```haskell 181 | makeUnique :: Person -> IO UniquePerson 182 | makeUnique p = do 183 | Graph nodes rootId <- reifyGraph p 184 | 185 | let makeIdentity (uid,_) = do 186 | uniq <- newUnique 187 | return (uid, uniq) 188 | 189 | identities <- mapM makeIdentity nodes 190 | 191 | let deref uid = UniquePerson name uniqueFriends identity where 192 | uniqueFriends = map deref friends 193 | identity = fromJust $ lookup uid identities 194 | Person' name friends = fromJust $ lookup uid nodes 195 | 196 | return $ deref rootId 197 | ``` 198 | 199 | Now we can test that the identities are mapped correctly: 200 | 201 | ```haskell 202 | main = do 203 | let bob = Person "Bob" [fred, alice] 204 | fred = Person "Fred" [bob] 205 | alice = Person "Alice" [fred] 206 | 207 | bob' <- makeUnique bob 208 | let [fred', alice'] = friends bob' 209 | 210 | -- Test that Bob and Alice know the exact same Fred 211 | print $ fred' `is` (friends alice' !! 0) 212 | ``` 213 | 214 | Finally, it's worth noting that `reifyGraph` doesn't in any way cache values from previous calls, so calling `makeUnique bob` and `makeUnique fred` will produce two separate `UniquePerson` graphs with no shared identities. 215 | 216 | 217 |
218 | Sami Hangaslammi <[sami.hangaslammi@leonidasoy.fi](mailto://sami.hangaslammi@leonidasoy.fi)> 219 | 220 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 221 | -------------------------------------------------------------------------------- /2013/2013-02-19-typesafe-tictactoe.md: -------------------------------------------------------------------------------- 1 | # A Game of Type-Safe Tic-Tac-Toe 2 | 3 | I held a functional programming workshop recently where the topic was 4 | implementing a browser based Tic-Tac-Toe on top of a Haskell web server. This is 5 | a rundown of the resulting game, where I demonstrate some of the ways to 6 | leverage Haskell's type system to gain stronger compile time guarantees. 7 | 8 | While many of these techniques are slightly overkill for such as simple game, 9 | they will hopefully give you some ideas that you can take advantage of in 10 | more complicated Haskell projects. 11 | 12 | 13 | ## A Kind of Piece 14 | 15 | The fundamental elements of Tic-Tac-Toe are the game pieces, which can be either 16 | Xs or Os. This maps naturally to the simple, algebraic data-type 17 | 18 | ```haskell 19 | data Piece = X | O deriving Eq 20 | ``` 21 | 22 | 23 | However, we can encode several interesting properties on the type-level by 24 | promoting the `Piece` type to a type-kind and thus, `X` and `O` into types. This 25 | is done by the language extension [`DataKinds`](http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/kind-polymorphism-and-promotion.html#promotion) which was 26 | introduced in GHC 7.4.1. 27 | 28 | We can use the types `X` and `O` as [phantom types](http://www.haskell.org/haskellwiki/Phantom_type) 29 | to tag other types. For example, instead of just having a `Player` type, we can 30 | have `Player X` and `Player O` and when those players make moves on the game 31 | board, the moves can be tagged as `Move X` and `Move O`. This adds additional 32 | compile-time guarantees to our program, because we can formulate the APIs so 33 | that it's impossible for the `Player X` to make a `Move O` due to a programming 34 | error if the program type-checks. 35 | 36 | Sometimes we need to reify the `Piece` type into `Piece` value, so define the 37 | following type-class 38 | 39 | ```haskell 40 | class ReifyPiece (p :: Piece) where 41 | reifyPiece :: f p -> Piece 42 | 43 | instance ReifyPiece X where 44 | reifyPiece _ = X 45 | 46 | instance ReifyPiece O where 47 | reifyPiece _ = O 48 | ``` 49 | 50 | The `p :: Piece` in the type-class declaration is a [kind signature](http://www.haskell.org/ghc/docs/latest/html/users_guide/other-type-extensions.html#kinding) for the 51 | type variable `p`. This restricts the type of `p` to those types that have the 52 | kind `Piece`, i.e. the types `X` and `O`. 53 | 54 | Since data-types that are promoted from constructors cannot have any values, 55 | `X` and `O` are, in practice, limited to appearing in phantom types. 56 | Therefore the `reifyPiece` function takes in a value of some parametric type 57 | `f` that has `p` as a type-parameter. Now we can, for example, call `reifyPiece` 58 | with any value of type `Move X` and get back the `Piece` value `X`. 59 | 60 | 61 | ## The Order of Play 62 | 63 | Using the `Piece` kind, we can even encode in the types the fact that `Player X` 64 | and `Player O` must take alternating turns when playing the game. For this, we 65 | need a [type family](http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/type-families.html) 66 | for switching from `X` to `O` and back. 67 | 68 | ```haskell 69 | type family Other (p :: Piece) :: Piece 70 | type instance Other X = O 71 | type instance Other O = X 72 | ``` 73 | 74 | The type family `Other` is the type-level equivalent of the function 75 | 76 | ```haskell 77 | other :: Piece -> Piece 78 | other X = O 79 | other O = X 80 | ``` 81 | 82 | Even though writing type-level functions is a bit more limited and verbose the 83 | relationship to value-level functions should be quite evident. 84 | 85 | 86 | Now, to encode the current state of the game, we use the `Game` data type 87 | 88 | ```haskell 89 | data Game (turn :: Piece) = Game Board (GameStatus turn) 90 | ``` 91 | 92 | The `turn` type-variable indicates whether it's currently X's or O's turn to 93 | play. `GameStatus` is a [GADT](http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/data-type-extensions.html#gadt) (generalized algebraic data type) which indicates whether the game 94 | still expects a new turn or if it has ended in a victory or draw. 95 | 96 | ```haskell 97 | type ProcessMove turn = Move turn -> Maybe (Game (Other turn)) 98 | 99 | data GameStatus (turn :: Piece) where 100 | Turn :: ProcessMove turn -> GameStatus turn 101 | Draw :: GameStatus turn 102 | Win :: Piece -> GameStatus turn 103 | ``` 104 | 105 | The `ProcessMove` type alias describes a function that takes a move from the 106 | player whose turn it currently is and returns a new `Game` value for the 107 | opponent's turn (or `Nothing` if the move was invalid). Since the return value 108 | has the phantom type `Other turn` this causes type parameter to switch between 109 | `X` and `O`. 110 | 111 | 112 | `Board` and `Position` are opaque types that we interface with using the 113 | following functions. 114 | 115 | ```haskell 116 | newBoard :: Board 117 | putPiece :: Piece -> Position -> Board -> Board 118 | isFull :: Board -> Bool 119 | (!) :: Board -> Position -> Maybe Piece 120 | ``` 121 | 122 | 123 | In addition, we have the value `lanes` which lists all the possible lanes that 124 | can be filled up to win teh game (i.e. rows, columns and diagonals) and the 125 | accessor `movePos` which returns the position where a move was played. 126 | 127 | ```haskell 128 | lanes :: [[Position]] 129 | movePos :: Move turn -> Position 130 | ``` 131 | 132 | The only function we expose from the game logic module is 133 | 134 | ```haskell 135 | newGame :: Game X 136 | newGame = Game newBoard $ Turn $ makeMove newBoard 137 | ``` 138 | 139 | The type of `newGame` encodes the property that `X` always goes first in a 140 | newly created game and the `makeMove` function alternates between accepting 141 | `Move X` and `Move O` values to produce the next turn of the game. 142 | 143 | ```haskell 144 | makeMove :: CyclicTurn turn => Board -> ProcessMove turn 145 | makeMove board move 146 | | Nothing <- board ! pos = Game board' <$> (gameOver <|> nextTurn) 147 | | otherwise = Nothing 148 | where 149 | piece = reifyPiece move 150 | pos = movePos move 151 | board' = putPiece piece pos board 152 | 153 | gameOver = victory <|> draw 154 | nextTurn = Just $ Turn $ makeMove board' 155 | 156 | draw = maybeIf (isFull board') Draw 157 | victory = msum $ map check lanes 158 | 159 | check lane = maybeIf allMatch $ Win piece where 160 | allMatch = all (\p -> board' ! p == Just piece) lane 161 | ``` 162 | 163 | The `CyclicTurn` constraint is to help GHC realize that any `Move turn` can 164 | be reified to a `Piece` since `Move X` is an instance of `ReifyPiece` as is 165 | `Move O` and for all types `t` of the `Piece` kind `Other (Other t)` is equal to 166 | `t`. 167 | 168 | ```haskell 169 | type CyclicTurn turn = 170 | ( ReifyPiece turn 171 | , ReifyPiece (Other turn) 172 | , Other (Other turn) ~ turn 173 | ) 174 | ``` 175 | 176 | Let's go through the `makeMove` function part by part. 177 | 178 | ```haskell 179 | makeMove board move 180 | | Nothing <- board ! pos = Game board' <$> (gameOver <|> nextTurn) 181 | | otherwise = Nothing 182 | ``` 183 | 184 | The guard verifies that the move is valid (i.e. the position on the board is 185 | empty) with a [pattern guard](http://research.microsoft.com/en-us/um/people/simonpj/Haskell/guards.html). 186 | We do not have to check that the given position is within game board bounds 187 | because `Position` is an opaque data type for which constructing invalid values 188 | is impossible. 189 | 190 | If the move is valid, we return a `Game` value with the updated board (`board'`) 191 | and a new `GameStatus` which is either `gameOver` or `nextTurn`. 192 | 193 | ```haskell 194 | gameOver = victory <|> draw 195 | nextTurn = Just $ Turn $ makeMove board' 196 | ``` 197 | 198 | `gameOver` happens with either `victory` or `draw` which both have the type 199 | `Maybe (GameStatus turn)`. `nextTurn` is always a `Just`, so the first guard in 200 | the function can never return a `Nothing`. `nextTurn` calls `makeMove` 201 | recursively and because the return type of `makeMove` is `Maybe (Game (Other turn))` 202 | type-inference will handle switching the `X` to `O` and `O` to `X` in the 203 | recursive call. 204 | 205 | ```haskell 206 | draw = maybeIf (isFull board') Draw 207 | victory = msum $ map check lanes 208 | 209 | check lane = maybeIf allMatch $ Win piece where 210 | allMatch = all (\p -> board' ! p == Just piece) lane 211 | ``` 212 | 213 | Checking for draw or victory is straightforward with the `Board` API we are 214 | given. `maybeIf` is a small utility function for returning a `Maybe` value 215 | based on a boolean predicate. 216 | 217 | ```haskell 218 | maybeIf :: Bool -> a -> Maybe a 219 | maybeIf p a = if p then Just a else Nothing 220 | ``` 221 | 222 | 223 | ## Interfacing with the Unsafe World of JavaScript 224 | 225 | The actual game implementation runs as a web server to which browsers connect 226 | using [WebSockets](http://en.wikipedia.org/wiki/WebSocket). There's a thin 227 | abstraction layer on top of raw WebSockets which introduces two concepts: 228 | notifications and requests. Notifications are fire-and-forget sort of messages 229 | while requests require an answer from the other end of the connection. 230 | 231 | The messaging layer uses JSON for serialization and, naturally, when the 232 | Haskell program receives a new message and deserializes it, there is no static 233 | type information available. If we look at requests which are initiated by the 234 | server, one way to determine the response type is to let the caller decide 235 | it via return value polymorphism. 236 | 237 | ```haskell 238 | request :: (ToJSON request, FromJSON response) => request -> IO response 239 | ``` 240 | 241 | The `response` type parameter will usually get inferred from the calling context, 242 | but this can sometimes result in hard to find bugs if, due to faulty implementation, 243 | the reponse type ends up being inferred as something other than we expected. 244 | Another weakness in this approach is that when using polymorphic functions, the 245 | reponse type might be left ambiguous, forcing us to add inline type annotations 246 | at the function call site. 247 | 248 | Because of the above reasons, the messaging layer requires requests to have 249 | the kind (* -> *) so that every request type contains the type of the expected 250 | response. I.e. 251 | 252 | ```haskell 253 | request :: (Request request, FromJSON response) => request response -> IO response 254 | ``` 255 | 256 | Now we can use a GADT to define the different requests in our communication 257 | protocol. For example: 258 | 259 | ```haskell 260 | data ServerRequest response where 261 | AskName :: ServerRequest String 262 | AskMove :: ServerRequest (Move t) 263 | AskNewGame :: ServerRequest Bool 264 | ``` 265 | 266 | 267 | The `Request` type-class is defined as 268 | 269 | ```haskell 270 | class Request r where 271 | reqToJSON :: r a -> Value 272 | reqFromJSON :: Value -> Result (Some r) 273 | ``` 274 | 275 | Since we cannot know the correct phantom type for a request that we deserialize 276 | from some arbitrary JSON string, we need to erase the phantom type (which indicates 277 | the expected type for the response) using the helper GADT `Some`. 278 | 279 | ```haskell 280 | data Some t where 281 | Some :: (FromJSON x, ToJSON x) => t x -> Some t 282 | ``` 283 | 284 | Now erasing the phantom type might seem like it undermines the whole extra 285 | type-safety, but once again, it's the properties of GADTs that come to our 286 | rescue. Handlers for incoming requests are registered with the function 287 | 288 | ```haskell 289 | onRequest 290 | :: Request req 291 | => Connection 292 | -> (forall resp. => req resp -> IO resp) 293 | -> STM () 294 | ``` 295 | 296 | Since the constructor `Some` loses all information about the type parameter of 297 | the request, our function that handles a deserialized request must be able to 298 | handle any type. We indicate this with a [rank-2 type](http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/other-type-extensions.html#universal-quantification). 299 | 300 | This is different from the signature 301 | 302 | ```haskell 303 | onRequest 304 | :: Request req 305 | => Connection 306 | -> (req resp -> IO resp) 307 | -> STM () 308 | ``` 309 | 310 | in that for the rank-1 version, the concrete types of `req` and `resp` are fixed 311 | when the function is called, whereas for the rank-2 version the function given 312 | as a parameter stays polymorphic. 313 | 314 | The erased phantom type can be recovered by matching to the constructors of 315 | the request GADT, because each constructor is associated with a specific 316 | phantom type. For example, handling the `ServerRequest` defined above might 317 | look something like 318 | 319 | ```haskell 320 | onRequest conn $ \req -> case req of 321 | AskName -> return "John Doe" 322 | AskNewGame -> return True 323 | ``` 324 | 325 | As you can see, the different branches of the case expression can return 326 | different types based on the GADT constructor that was matched. And best of all, 327 | if we tried to return the wrong type, for example 328 | 329 | ```haskell 330 | AskName -> return False 331 | ``` 332 | 333 | we would get a compile time type error. 334 | 335 | 336 | ## Taking Sides 337 | 338 | As I mentioned earlier, the `Piece` kind is used to tag the types `Move` and 339 | `Player` as well. However, the way the game works is that when players connect 340 | to the server they are put to a queue and at this point they are not yet playing 341 | with either X's or O's. The `Player` type is actually defined like this 342 | 343 | ```haskell 344 | data User (piece :: Maybe Piece) = User 345 | { userName :: String 346 | , userConn :: Connection 347 | } 348 | 349 | type NewPlayer = User Nothing 350 | type Player piece = User (Just piece) 351 | ``` 352 | 353 | Since the `DataKinds` extension promotes _all_ types into kinds, this includes 354 | standard library types such as `Maybe`. That means that we can use the `Maybe` 355 | kind to encode optional phantom types. 356 | 357 | 358 | The user module exports the following functions: 359 | 360 | ```haskell 361 | newUser :: String -> Connection -> NewPlayer 362 | assignSides :: NewPlayer -> NewPlayer -> Random (Player X, Player O) 363 | stripSide :: Player t -> NewPlayer 364 | ``` 365 | 366 | For receiving moves from the players, we use the function 367 | 368 | ```haskell 369 | requestMove :: Player piece -> IO (Future (Move piece)) 370 | ``` 371 | 372 | which ensures that the move has the same `Piece` tag that the issuing player 373 | has. 374 | 375 | 376 | ## Playing the Game 377 | 378 | When there are at least two players queued up on the server, the server pairs 379 | them up, assigns random sides with the `assignSides` function and starts a 380 | thread which runs the actual game: 381 | 382 | ```haskell 383 | type Cyclic a b = (a ~ Other b, b ~ Other a) 384 | 385 | playGame :: TChan NewPlayer -> (Player X, Player O) -> IO () 386 | playGame queue (px, po) = start >> play >> both requeue where 387 | 388 | start = atomically $ do 389 | notify (userConn px) $ FoundOpponent $ userName po 390 | notify (userConn po) $ FoundOpponent $ userName px 391 | 392 | play = playTurn px po newGame 393 | 394 | playTurn :: Cyclic t t' => Player t -> Player t' -> Game t -> IO () 395 | playTurn p p' (Game b st) = sendBoard >> foldGameStatus turn draw win st where 396 | turn f = loop where 397 | loop = requestMove p >>= resolveMove 398 | resolveMove = join . atomically . foldFuture disconnect nextTurn 399 | disconnect = atomically $ notifyResult p' WonGame 400 | nextTurn m = maybe loop (playTurn p' p) (f m) 401 | 402 | draw = atomically $ both $ \u -> notifyResult u DrawGame 403 | 404 | win _ = atomically $ do 405 | notifyResult p LostGame 406 | notifyResult p' WonGame 407 | 408 | sendBoard = atomically $ both $ \u -> notify (userConn u) (GameBoard b) 409 | 410 | notifyResult u = notify (userConn u) . GameOver 411 | 412 | both :: Monad m => (forall t. Player t -> m ()) -> m () 413 | both op = op px >> op po 414 | 415 | requeue :: Player t -> IO () 416 | requeue p = void $ forkIO $ do 417 | yes <- request (userConn p) AskNewGame 418 | when yes $ atomically $ writeTChan queue $ stripSide p 419 | ``` 420 | 421 | While I'm not going to go into too much detail here, the part that is relevant for this 422 | type-safety article is the way that `playTurn` takes in `Player X` and 423 | `Player O` and then swaps them around in the recursive call in `nextTurn`. This 424 | way the first parameter always contains the player whose turn it is, and the tag 425 | `X` or `O` has to match the type of move `Game` is expecting for this turn. This 426 | way, were we to, for example, forget to swap the two players, we would get a 427 | compile time type-error, preventing the same player from getting to play all the 428 | turns. 429 | 430 | The full source code for the game can be browsed at [GitHub](https://github.com/leonidas/lambda-webdev/tree/type-safe). 431 | 432 | 433 |
434 | Sami Hangaslammi <[sami.hangaslammi@leonidasoy.fi](mailto://sami.hangaslammi@leonidasoy.fi)> 435 | 436 | Leonidas Oy <[http://leonidasoy.fi](http://leonidasoy.fi)> 437 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Leonidas Oy 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leonidas CodeBlog 2 | 3 | This is the technical side blog of [Leonidas](http://leonidasoy.fi/). 4 | 5 | ## Latest Articles 6 | 7 | * 2013-02-19: [A Game of Type-Safe Tic-Tac-Toe](https://github.com/leonidas/codeblog/blob/master/2013/2013-02-19-typesafe-tictactoe.md) 8 | * 2013-01-14: [Observable Sharing Using Data.Reify](https://github.com/leonidas/codeblog/blob/master/2013/2013-01-14-observable-sharing.md) 9 | 10 | ## Older Articles 11 | 12 | ### 2012 13 | 14 | * 2012-02-21: [Concatenative Haskell Part II: Custom DSL Syntax Using QuasiQuotes](https://github.com/leonidas/codeblog/blob/master/2012/2012-02-21-concatenative-haskell-ii-dsl.md) 15 | * 2012-02-17: [Concatenative, Row-Polymorphic Programming in Haskell](https://github.com/leonidas/codeblog/blob/master/2012/2012-02-17-concatenative-haskell.md) 16 | * 2012-01-17: [Purely Functional, Declarative Game Logic Using Reactive Programming](https://github.com/leonidas/codeblog/blob/master/2012/2012-01-17-declarative-game-logic-afrp.md) 17 | * 2012-01-13: [Implementing Semantic Anti-Templating With jQuery](https://github.com/leonidas/codeblog/blob/master/2012/2012-01-13-implementing-semantic-anti-templating-with-jquery.md) 18 | * 2012-01-08: [Generalizing Streams into Coroutines](https://github.com/leonidas/codeblog/blob/master/2012/2012-01-08-streams-coroutines.md) 19 | 20 | ### 2011 21 | 22 | * 2011-12-27: [Basic Tutorial of Template Haskell](https://github.com/leonidas/codeblog/blob/master/2011/2011-12-27-template-haskell.md) 23 | * 2011-12-21: [Statically Typed Vector Algebra Using Type Families](https://github.com/leonidas/codeblog/blob/master/2011/2011-12-21-static-vector-algebra.md) 24 | * 2011-12-18: [NFA in a Single Line of Haskell](https://github.com/leonidas/codeblog/blob/master/2011/2011-12-18-haskell-nfa.md) 25 | 26 | ## License 27 | 28 | All source code contained in the blog articles is placed under the MIT license 29 | unless mentioned otherwise. 30 | --------------------------------------------------------------------------------