├── Tutorial.pdf ├── tut ├── Makefile ├── Tut3.md ├── Tut2.md └── Tut1.md ├── ColoredVersion.pdf ├── Makefile ├── README.md └── Tutorial.lhs /Tutorial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamuelSchlesinger/HaskellTutorial/HEAD/Tutorial.pdf -------------------------------------------------------------------------------- /tut/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | git add * 3 | git commit -m "another commit" 4 | git push -u origin master 5 | -------------------------------------------------------------------------------- /ColoredVersion.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamuelSchlesinger/HaskellTutorial/HEAD/ColoredVersion.pdf -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | Tutorial: 2 | lhs2TeX -o Tutorial.tex Tutorial.lhs 3 | pdflatex Tutorial.tex 4 | rm *.aux *.log *.ptb *.tex *.out 5 | 6 | view: 7 | make 8 | evince Tutorial.pdf 9 | 10 | clean: 11 | rm *.aux *.log *.ptb *.tex *.pdf 2> /dev/null 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Haskell Tutorial 2 | 3 | I wanted to fill a few pages with some of the Haskell knowledge I've gotten in the last few months. 4 | 5 | Tutorial.lhs is valid literate Haskell, you can load it into ghci via 6 | 7 | > ghci Tutorial.lhs 8 | 9 | The colored version is not the same as the one in Tutorial.lhs, but it has a little more in it. It 10 | is not literate Haskell. 11 | -------------------------------------------------------------------------------- /tut/Tut3.md: -------------------------------------------------------------------------------- 1 | ## Patterns from Math 2 | 3 | In programming, we often write functions over data structures to modify their internals, or perhaps 4 | to indicate the way to modify something in the future. Functions do this, they map elements of types 5 | to other types, allowing you to use them to abstract over this notion of modifying data structures. 6 | There happens to be an even more general formulation of this idea which came out of the body of 7 | mathematics called Category Theory. We won't cover this, but we'll cover the way it's used in 8 | Haskell, which is thankfully much simpler. In Haskell this is represented by a class, which if you 9 | haven't read about before you can totally go do that in Learn You a Haskell, as I encouraged in the 10 | first bit. 11 | 12 | ```Haskell 13 | 14 | class Functor f where 15 | fmap :: (a -> b) -> (f a -> f b) 16 | 17 | ``` 18 | 19 | Essentially, this class lets us talk about all types which give us the ability to lift a function 20 | between two domains, to a function between the two domains mapped over by f, which is a type level 21 | function, a template by C++ lingo, or a generic in Java lingo. This generalizes the following sort 22 | of pattern: 23 | 24 | The rules that we want implementations of Functor to obey are the following: 25 | 26 | ```Haskell 27 | 28 | fmap f . fmap g = fmap (f . g) x 29 | fmap id = id 30 | 31 | ``` 32 | 33 | This lets us optimize lots of code, for instance see the following, wherein we assume that the 34 | data structure we are mapping these functions over is distributed throughout some huge database: 35 | 36 | ```Haskell 37 | 38 | y = (fmap f1 . fmap f2 ... . fmap fn) x = fmap (f1 . f2 . ... . fn) x 39 | 40 | ``` 41 | 42 | The latter way would be much more convenient, and we can avoid a helluva lot of cache misses if x 43 | is distributed in memory. 44 | 45 | ```Haskell 46 | 47 | class Functor f => Applicative f where 48 | pure :: a -> f a 49 | (<*>) :: f (a -> b) -> f a -> f b 50 | 51 | ``` 52 | -------------------------------------------------------------------------------- /tut/Tut2.md: -------------------------------------------------------------------------------- 1 | ## And Then There Was IO 2 | 3 | In Haskell, we want to make sure of the following invariant: 4 | 5 | ```Haskell 6 | 7 | f = g 8 | 9 | e = ... f ... if and only if e = ... g ... 10 | 11 | ``` 12 | 13 | What this means is that we want a much more strong notion of "assignment" than 14 | other language. It's so strong, that calling the declaration "f = g" is really 15 | a misnomer. What the above invariant means is that if we actually know that f 16 | is equal to g, then we should really be able to replace f with g anywhere that f 17 | is used and not modify the meaning of our code. In fact, we can also evaluate 18 | our expressions this way, recalling map from the previous section: 19 | 20 | ```Haskell 21 | 22 | map (+ 1) xs = case xs of 23 | [] -> [] 24 | x : xs -> f x : map f xs 25 | 26 | map f [1, 2, 3, 4] 27 | 2 : map f [2, 3, 4] 28 | 2 : 3 : map f [3, 4] 29 | 2 : 3 : 4 : map f [4] 30 | 2 : 3 : 4 : 5 : map f [] 31 | 2 : 3 : 4 : 5 : [] 32 | 33 | ``` 34 | 35 | For one thing, this is an obvious way to show to ourselves that our map function actually 36 | does what I claimed it to do. Something that's interesting is thinking about how this would 37 | work in a language like Java, where we have statements and blocks which don't even have types 38 | and can't interact smoothly with the other parts of the language. This ability to transform 39 | our programs is great from the perspective of correctness and the ability to inspect the execution 40 | of our programs on concrete and unspecified inputs. 41 | 42 | This all appears great, but consider the following program: 43 | 44 | ```Haskell 45 | 46 | getChars :: FilePath -> [Char] 47 | 48 | length (getChars "words.txt") 49 | 50 | ``` 51 | 52 | If we execute this function while the state of our machine is that the file "words.txt" is of 53 | length n, or length m, we know that at different days n may or may not equal m, depending on what 54 | is happening to our filesystem. This introduces nondeterminism, and of course is something that 55 | eliminates the type of equality we had gotten earlier on from analyzing map on that input. Let's 56 | try to see that in action: 57 | 58 | 59 | ```Haskell 60 | 61 | x :: Integer 62 | x = if length (getChars "words.txt") == 10 then "MY WORDS ARE 10" else "my words are different" 63 | 64 | ``` 65 | 66 | So now we have this Integer x which, by our languages model with this getChars function, is of 67 | type Integer, but in fact it is really a function of the state of the world in which we execute 68 | this code as well, as we know that if I "echo aaaaaaaaaa > words.txt" this would clearly change the 69 | way the code will execute. Hold up, we have this problem which is that this Integer retrieved is 70 | not just an Integer, but an Integer function of the state of the RealWorld! We can just write this 71 | in our language, using primitives offered by GHC, the Haskell compiler which you should be using. 72 | 73 | ```Haskell 74 | 75 | type IO a = State RealWorld -> (State RealWorld, a) 76 | 77 | ``` 78 | 79 | This means that IO a is literally a function from the state of the real world, to another state 80 | of the real world plus some a which was computed in the process of that change. Understanding this 81 | abstraction is not necessary for our being able to use the IO faculties we have in Haskell. This is 82 | our model for interactions with the outside world, and we can interact with this model really 83 | painlessly using certain notions from a body of mathematical knowledge referred to as category theory which I'll discuss briefly in the next bit. 84 | -------------------------------------------------------------------------------- /tut/Tut1.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This is meant to be a concise tutorial which will show you the Haskell programming language 4 | by example and get to certain things which aren't often shown in the tutorials which target beginners. I will assume that you have access to resources like [Learn You a Haskell](http://learnyouahaskell.com/) and will really blow through a lot of pedagogy to show you the cool thing you can accomplish 5 | once you understand the basic machinery. I will intentionally keep my discussion as conversational 6 | and minimal in terms of required knowledge, but please raise an issue if something needs clarification. Below is the definition of a polymorphic linked list in Haskell. 7 | 8 | ```Haskell 9 | 10 | data List a 11 | = More a (List a) 12 | | NoMore 13 | 14 | ``` 15 | 16 | What this code does for us is introduce a new type called List which takes a function a in a 17 | similar way to Java generics or C++ templates, as well as an invariant for List which says that 18 | if we know that l1 is a "List Int", then we know that it takes one of two forms, for some unknown n 19 | and l2: 20 | 21 | ```Haskell 22 | 23 | l1 = More n l2 24 | or 25 | l1 = NoMore 26 | 27 | ``` 28 | 29 | This is great! With this knowledge in hand, we can use what's called in Haskell a "case statement", 30 | which I can demonstrate with the following example which takes the length of a list: 31 | 32 | ```Haskell 33 | 34 | length :: List a -> Integer 35 | length list = case list of 36 | More first rest -> 1 + length rest 37 | NoMore -> 0 38 | 39 | ``` 40 | 41 | What the above declaration states is that, given any List, I know it can take at most two forms, so 42 | I can check which one it is. If there are NoMore elements in the list, this means that it is of 43 | length 0, so I can simply return 0. If there's one element in the first position of the list plus 44 | More, then I should add 1 for that element onto the length of the rest of the elements. 45 | This is the logical way I understand the above algorithm and many others, by reasoning about every 46 | distinct case of input that may come in, and being able to do this case by case analysis inside of 47 | my programs as well feels really productive. For reference, in Haskell, the list type is denoted 48 | by this built in notation instead of the way we've defined it: 49 | 50 | ```Haskell 51 | 52 | data [a] 53 | = a : [a] 54 | | [] 55 | 56 | ``` 57 | There is also syntactic sugar for lists: 58 | 59 | ```Haskell 60 | 61 | lengthTwo :: [a] -> Bool 62 | lengthTwo xs = case xs of 63 | [a1, a2] -> True 64 | _ -> False 65 | 66 | ``` 67 | 68 | The things I've introduced so far, albeit briefly, are to me the reason why Haskell is the most 69 | productive programming language to use and I'm pretty certain when I say that Haskell and it's derivatives (Purescript, Elm, etc) really do have the best facilities for this type of programming. OCaml is definitely a close second but there are lousily long keywords in certain areas that just makes me miss the Haskell syntax. The following two functions are very important and illustrate the essential flavor of functional programming: 70 | 71 | ```Haskell 72 | 73 | filter :: (a -> Bool) -> [a] -> [a] 74 | filter p as = case as of 75 | a : as -> if p a 76 | then a : filter p as 77 | else filter p as 78 | [] -> [] 79 | 80 | map :: (a -> b) -> [a] -> [b] 81 | map f as = case as of 82 | a : as -> f a : map f as 83 | [] -> [] 84 | 85 | ``` 86 | 87 | What filter does is the following: given a function p from a to Bool, and a list of as, filter p as 88 | gives me a list of as for which I can be sure all of them satisfy the predicate. This is even obvious in the declaration itself, as it runs over the list creating a new one, only adding each element if they satisfy the predicate p supplied. 89 | 90 | What map does is the following: given a function f from a to b, and a list of as, map f as will be a list with the same structure as the one passed in, but with each a being mapped to f a. 91 | 92 | These functions are usually prefaced with countless examples of why this is useful and these patterns appear everywhere, but I'll assume that the reader is versed in programming in some other language and it will be obvious that these patterns pop up everywhere. A common theme of Haskell is that the things called "patterns" in other languages tend to be implemented as concrete abstractions in the Haskell provides you to talk about types, programs, and their interactions. 93 | 94 | -------------------------------------------------------------------------------- /Tutorial.lhs: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{hyperref} 3 | %include polycode.fmt 4 | 5 | \title{Haskell Tutorial} 6 | \author{Samuel Schlesinger} 7 | 8 | \begin{document} 9 | 10 | \maketitle 11 | 12 | \section{Purpose} 13 | 14 | \paragraph{} 15 | Many tutorials on various programming languages are either directed towards people with little to no 16 | experience in programming, or towards people with experience in some other particular programming language. 17 | The former approach is generally structured pedantically and cautiously, as to not scare away the uninitiated. 18 | The latter approach often dives in and shows the reader code snippets side by side in order to let your 19 | knowledge in one language prop you up in your discovery of the other. I would like to accomplish neither of 20 | these, as each have been accomplished quite fully for Haskell in particular. 21 | 22 | \paragraph{} 23 | My focus is to show a language I love, \textbf{Haskell} to a demographic which I am a part of: 24 | \textbf{Undergraduate CS Students}, or people with a comparable knowledge base. Particularly, I will describe concepts from \textbf{Data Structures} and \textbf{Algorithms}, though I will try to include a brief explanation of each concept discussed. I also assume that you are familiar with at least one of the most popular 25 | programming languages as a part of the assumption that you have knowledge base similar to an undergraduate. 26 | 27 | \paragraph{} 28 | To tell you a little bit about myself, I'm a student at Clark University entering my Junior year. I study 29 | CS and maths, and currently I'm working my first internship at Autodesk. My experience in Haskell is self 30 | taught, though I want to emphasize that this is only possible through the great community that Haskell has 31 | to offer. Throughout this reading, if you have any questions, I am reachable via reddit at /u/SSchlesinger 32 | and the subreddit /r/Haskell is also a great resource, along with StackOverflow and the other 33 | usual things. If you have code that you think is interesting or cool that you've written, posting it on 34 | the Haskell subreddit is very likely to get you feedback, often even from some of the more prominent members of the Haskell community. I will likely gather a set of resources alongside this document to supplement it. 35 | This document will be hosted at \href{https://github.com/SamuelSchlesinger/HaskellTutorial}{Haskell Tutorial}. It will be subject to changes, so if you want a particular version, make sure you save it. 36 | 37 | \clearpage 38 | 39 | \section{Setup} 40 | 41 | \paragraph{} 42 | In general, the easiest way of getting Haskell up and running is to install the \textbf{Haskell Platform}. 43 | There is support for the \textbf{Linux}, \textbf{OS X}, and \textbf{Windows} operating systems. A link 44 | which describes how to download it for each operating system can be found at 45 | \url{https://www.haskell.org/downloads#platform}. That being said, I currently am running the latest 46 | upload of GHC, as some nice new language extensions were included in it, and this can be found at 47 | \url{https://www.haskell.org/ghc/}. All code in this document should be executable from most Haskell 48 | distributions which implement Haskell 2010, the latest revision of the language. If any of it is not, please 49 | let me know. 50 | 51 | \subsection{Windows} 52 | The Haskell Platform can be installed at \url{https://www.haskell.org/platform/windows.html}. There are 53 | additional instructions for setting up, but recently when I installed it on my work machine, WinGHCi didn't 54 | run perfectly for me, so I just added the GHCi executable to my path and ran it from cmd.exe. 55 | 56 | \subsection{OS X} 57 | There are a variety of ways of installing for OS X which can be found at \url{https://www.haskell.org/platform/mac.html}, and I won't pretend to know how any of them work because I've never used a Mac for this sort 58 | of thing. That being said, I know most people use brew, and I found a source saying that the following 59 | command should get it: 60 | 61 | \begin{quote} 62 | brew cask install haskell-platform. 63 | \end{quote} 64 | 65 | \subsection{Linux} 66 | The Linux installation can be found at \url{https://www.haskell.org/platform/linux.html}. I use Ubuntu, and 67 | the easiest way to get it should be: 68 | 69 | \begin{quote} 70 | sudo apt-get install haskell-platform 71 | \end{quote} 72 | 73 | \subsection{Environment} 74 | 75 | \paragraph{} 76 | For your environment, I have no IDE to suggest. The best resource out there to replace code completion is 77 | \href{https://www.haskell.org/hoogle/}{Hoogle}, a search engine through many Haskell libraries, including 78 | the standard ones. I will assume you will be using the terminal and that you have the commands 79 | \textbf{ghc} as well as \textbf{ghci} on your path going forward. If this is not clear or these are not 80 | working, please feel free to contact me for help. 81 | 82 | \paragraph{} 83 | The entirety of the document Tutorial.lhs is able to be loaded into GHCi. It may be of use to open a 84 | terminal up next to this document and open GHCi with: 85 | 86 | \begin{quote} 87 | 88 | ghci Tutorial.lhs 89 | 90 | \end{quote} 91 | 92 | This may allow you to play with some of the definitions and make sure I haven't screwed anything up 93 | as you read through this. Fair warning, however, GHCi does not let you make high level definitions in 94 | the same way that you can in an external file. If you'd like to make your own definitions in GHCi you 95 | can use a \textbf{let} statement or open a file on your own and load it into GHCi the way I described (you can put multiple files, i.e ghci x.hs y.hs ...), or with :l a.hs once you're in GHCi. If you get confused, 96 | :h within GHCi will show you your options, and there is good documentation online. 97 | 98 | \clearpage 99 | 100 | \section{First Principles} 101 | 102 | \paragraph{} 103 | I said that I wouldn't be starting from the basics and I won't, but even if you know how to program, if 104 | you haven't used Haskell I would read through this section. The concepts in here will not just follow you 105 | through the rest of this tutorial, but they will hopefully carry you. 106 | 107 | \subsection{Definitions} 108 | 109 | \paragraph{} 110 | In Java, C, Python, as well as the majority of modern programming languages, assignment is an action. 111 | This action is denoted by a variable name on the left, an equals sign, and some sort of value on the right. 112 | This notation is used in Haskell for something much stronger, which is something I'll refer to lightly as 113 | equality, but could be more strongly called propositional equality. This means that when I define something 114 | to be equal to something else, I can interchange these two things anywhere this definition is in scope and 115 | I will not modify the meaning of whatever greater expression they are a part of. As we all know, assignment 116 | is useful for a variety of reasons, not the least of which are brevity and control. This stronger version 117 | of assignment is useful for the same reasons, but it also gives us something called \textbf{referential 118 | transparency}, the strong notion of equality I described above, which lets you reason about the values 119 | you're representing without even discussing the memory locations you have to consider while using other 120 | programming languages. This is something typical of what is called the functional programming paradigm. 121 | 122 | \begin{code} 123 | 124 | myHugeNumber = 10000000000000000000000000000000000000000000 125 | 126 | myNewString = "yada yada yada" 127 | 128 | sliceOfPi = 3.14 129 | 130 | \end{code} 131 | 132 | \paragraph{} 133 | The definition I gave above might scare some of you in the following way. If you were writing some code 134 | in an imperative programming language like C\#, you might have defined a class which contains some variable 135 | you'd like to play with. As such, you might define the set and get methods for that variable and then 136 | change the value as you see fit. This immediately contradicts the notion I defined above. If you can change 137 | the value of something you've previously defined, then you can't simply replace the right and left hand 138 | sides of your definitions with each other willy nilly. As such, definitions are final in Haskell. They 139 | are similar to mathematical definitions in this way. Though this may seem weird to some, it allows for 140 | much nicer analysis of your programs in many cases. Above, myHugeNumber literally refers to that massive 141 | number on the right. It doesn't just have it currently stored in whatever location the symbol myHugeNumber 142 | represents, it actually \textbf{is} equivalent to that huge number, which is a much stronger statement 143 | than you'll get in almost any other programming language. 144 | 145 | \paragraph{} 146 | There are two fears that I believe come up when one learns this fact about Haskell and its immutable 147 | definitions. The first I see is about efficiency, asking how on earth one can make efficient algorithms 148 | if one has to create new variables whenever they want to change something. This is a valid concern, but 149 | the important thing to realize is that this strong notion of equality is true when it comes to what your 150 | code \textbf{means}, not necessarily in terms of how the compiler will implement it. The next concern has to 151 | do with certain patterns that people have learned to rely on quite heavily in the average CS curriculum, 152 | especially looping constructs (hopefully not gotos). I can assure you that there are replacements for these 153 | which, if written in the proper way, will compile to essentially the same machine code as your for loops 154 | do. 155 | 156 | \subsection{Literals} 157 | In Haskell, like most programming languages, there are some literal symbols. These include numbers, strings, 158 | and some other things. These include things like numbers, lists, characters, and strings 159 | (which are actually just lists of characters): 160 | 161 | \begin{code} 162 | 163 | myFavoriteNumbers = [5, 8, 24] 164 | 165 | oneString = "Matisyahu" 166 | 167 | oneChar = '*' 168 | 169 | stringsAreListsOfChars = ['M', 'a', 't', 'i', 's', 'y', 'a', 'h', 'u'] == oneString 170 | 171 | \end{code} 172 | 173 | \subsection{Names} 174 | 175 | \paragraph{} 176 | Each name in scope distinctly refers to one value. Type names must begin with a capital letter whereas 177 | variable names must be lowercase. 178 | 179 | \subsection{First Types} 180 | 181 | \paragraph{} 182 | No matter what modern language you use, there is some notion of a type. The general idea of a type is that 183 | it is some meaningful annotation alongside your values and variables which indicates what sort of thing each 184 | one is or is allowed to be. In C, this is a very weak notion, as you are allowed to cast types back and 185 | forth from one another and really the only hard and fast type you get is a strip of bits of some length 186 | hiding away in your computer. In Java, there are atomic types such as int and char, and then there are 187 | types which extend from Object, the base for creating data structures in the language. You are allowed to a 188 | large extent to change things from one type to another as you see fit. 189 | 190 | \paragraph{} 191 | In Haskell, the notion of a type has a very strong will. There is no automatic coercion between types, and 192 | to take a type to another type without a proper transformation you have to use an unsafe function that I 193 | will not name here. That being said, certain literals are overloaded such that the compiler will deduce 194 | what they are supposed to be and they will become that type. In particular, numbers will do this, as you can 195 | check for yourself by entering the following code into GHCi and using the :t command to inspect the 196 | types. The code below also shows the notation for asserting that a given name will refer to something of a 197 | certain type, as well as illustrates that the Integer type and the Int type are distinct, the first referring 198 | to the mathematical integers (within the bounds of your memory) and the second to a 32 bit Int (though 199 | technically I think the specification says that it only has to be 30 bits). 200 | 201 | \begin{code} 202 | 203 | myFloat :: Float 204 | 205 | myFloat = 10 206 | 207 | myInteger :: Integer 208 | 209 | myInteger = 10412421512512 210 | 211 | myTuple :: (Integer, Float) 212 | 213 | myTuple = (100, 53) 214 | 215 | myList :: [Char] 216 | 217 | myList = "hello yes this is a string" 218 | 219 | mrTrue :: Bool 220 | 221 | mrTrue = True 222 | 223 | \end{code} 224 | 225 | \subsection{Function Types} 226 | 227 | \paragraph{} 228 | We've seen a few basic types, but so far we've left out something rather important for programming, especially 229 | in a functional language, and that's functions. In Haskell, functions are supposed to mirror what they 230 | are defined to be in mathematics, and that is that every time a function f takes some input x, f(x) will 231 | return the same value. That being said, in Haskell we usually write f x instead, as we use so many functions 232 | that having all of those parentheses hanging around can distract from what's really going on. 233 | Concise and easy to read code is definitely a virtue. 234 | 235 | \begin{code} 236 | 237 | isZero :: Integer -> Bool 238 | 239 | isZero n = case n of 240 | 0 -> True 241 | _ -> False 242 | 243 | \end{code} 244 | 245 | \paragraph{} 246 | The above code gives us our first example of a function along with pattern matching. All the case 247 | construct does is take its argument n and try to match it with each pattern below in order. If it 248 | matches up with one, it evaluates the expression to its right. There is a more concise notation for 249 | this which is equivalent, shown below. 250 | 251 | \begin{code} 252 | 253 | isZero' 0 = True 254 | 255 | isZero' _ = False 256 | 257 | \end{code} 258 | 259 | \paragraph{} 260 | There is another way we could have written this code, using something called a guard, which is similar to 261 | pattern matching but uses expressions of type Bool to determine what to evaluate to. 262 | 263 | \begin{code} 264 | 265 | isZero'' n 266 | | n == 0 = True 267 | | otherwise = False 268 | 269 | \end{code} 270 | 271 | \paragraph{} 272 | Don't let otherwise fool you, it isn't anything fancy, it's simply defined as otherwise = True in the Prelude, 273 | which is the standard bunch of definitions which are automatically imported whenever you start up GHCi 274 | or compile your code with GHC. I have one more version of this function for you before we move on... 275 | 276 | \begin{code} 277 | 278 | isZero''' n = n == 0 279 | 280 | \end{code} 281 | 282 | \subsection{User Defined Types} 283 | 284 | \subsubsection{Type Synonyms} 285 | 286 | \paragraph{} 287 | There are a three ways that I know of to define types in Haskell. The first is the simplest one and it's 288 | solely present for the programmers pleasure, and this is a \textbf{type synonym}. 289 | 290 | \begin{code} 291 | 292 | type Vector3D = (Float, Float, Float) 293 | 294 | \end{code} 295 | 296 | \paragraph{} 297 | Cool, we've defined a Vector3D! Now whenever I want to write functions to do my physics homework, I can 298 | just write functions that give and take Vector3D's instead of (Float, Float, Float)'s. This is honestly 299 | more convenient than you'd think, and if used properly can really serve to let your code document itself. 300 | It has zero runtime overhead and it allows you to see the see what your code means later on if you use it right. 301 | Personally, I often use these in such a way that when I describe my algorithm out loud, I get to use the same 302 | vocabulary as within the code itself. That way, if I can get someone to understand a program with language, 303 | there is a mostly one to one mapping to the code from this initial comprehension. 304 | 305 | \subsubsection{Data Declarations} 306 | 307 | \paragraph{} 308 | Though these type synonym guys are cool, they don't really add anything to the representational capacity 309 | of the language. In order to add types which are actually new sorts of data we can encounter in our 310 | computation, we use something called a \textbf{data declaration}. This lets us define our own types of things 311 | in a very flexible way, but in a way that might seem too simple or "dumb" (in the sense of a dumb data type) 312 | , particularly coming from the land of object orientation. As an example, we could have defined our Vector3D 313 | type in the way we're about to define a Vector2D. 314 | 315 | \begin{code} 316 | 317 | data Vector2D = Vector2D Float Float 318 | 319 | \end{code} 320 | 321 | \paragraph{} 322 | To break down the above statement, it says that a Vector2D is a type, and the only way to construct it is 323 | to use the \textbf{data constructor} Vector2D, which, if we were to inspect in GHCi, has type Float -> Float 324 | -> Vector2D. Now we can use this with pattern matching in order to do define some operations for ourselves. 325 | 326 | \begin{code} 327 | 328 | addVector2D :: Vector2D -> Vector2D -> Vector2D 329 | addVector2D v w = case v of 330 | Vector2D a b -> case w of 331 | Vector2D c d -> Vector2D (a + c) (b + d) 332 | 333 | \end{code} 334 | 335 | \paragraph{} 336 | Great! This is very similar to what we did above. We can simplify this in the same way that we could for 337 | isZero'. 338 | 339 | \begin{code} 340 | 341 | addVector2D' (Vector2D a b) (Vector2D c d) = Vector2D (a + c) (b + d) 342 | 343 | \end{code} 344 | 345 | \paragraph{} 346 | We could also have written our Vector2D in a slightly different way, using something called \textbf{record syntax}. 347 | 348 | \begin{code} 349 | 350 | data Vector2D' = Vector2D' { x :: Float, y :: Float } 351 | 352 | myGoodVector = Vector2D' { x = 421, y = 0.21 } 353 | 354 | xOfMyGoodVector = x myGoodVector 355 | 356 | \end{code} 357 | 358 | \paragraph{} 359 | The above is a syntactic sugar to simulate the object/struct paradigm which can be found in C and Java. One 360 | particularly good use case for it is when you have a data type which you'll be adding or removing fields 361 | to, perhaps because you haven't decided what you need to store in it, but even if you use this notation, you can still pattern match on Vector2D' f1 f2 and use it as a normal constructor. 362 | 363 | \paragraph{} 364 | Something else we can do in a data declaration is declare a bunch of different sorts of things a type might 365 | be. This could be useful if we're defining a common type which can take many different forms. The most common 366 | way in which this is used is if we have some function which might return some value that we want, but it also 367 | could not have anything for us. 368 | 369 | \begin{code} 370 | 371 | data PerhapsInt = GotOneHere Int | NotToday 372 | 373 | \end{code} 374 | 375 | \paragraph{} 376 | This time, we had to name our data constructors something different than our type name, cause there's more than one of them. That being said, we've already seen a type like this. A list either has an element 377 | and another list, the tail, or it can be empty. The constructors for lists are (:) and [], and I'll use them 378 | below to make this apparent. 379 | 380 | \begin{code} 381 | 382 | type IntPairs = [(Int, Int)] 383 | 384 | lookupTheInt :: IntPairs -> Int -> Int 385 | lookupTheInt ((x, y):rest) k 386 | | k == x = y 387 | | otherwise = lookupTheInt rest k 388 | 389 | \end{code} 390 | 391 | \paragraph{} 392 | This function does a rather obvious thing. Given a list of IntPairs, it checks if the first pair's left 393 | element matches the key we're searching for. If it does, we return the value on the right, otherwise we 394 | lookupTheInt in the rest of the list. What happens if we reach the empty list, though? Try it in GHCi. 395 | What you should see is an Exception with a message saying that there are "Non-exhaustive patterns in 396 | lookupTheInt". If you look at lookupTheInt's definition, this is apparently true. There is no match for 397 | lookupTheInt [] k, so when the code compiles it puts an error there. To be explicit, the pattern matching 398 | above will be converted into a pattern matching case statement, and in the bottom, there will be a \_, which 399 | matches anything, and it will probably return an error with an error message similar to what you saw. In 400 | order to avoid this problem, we use PerhapsInt. 401 | 402 | \begin{code} 403 | 404 | maybeLookupTheInt :: IntPairs -> Int -> PerhapsInt 405 | maybeLookupTheInt [] _ = NotToday 406 | maybeLookupTheInt ((x, y):rest) k 407 | | k == x = GotOneHere y 408 | | otherwise = maybeLookupTheInt rest k 409 | 410 | \end{code} 411 | 412 | \paragraph{} 413 | In fact, this pattern is so common in Haskell that, in the Prelude, there is a type which does exactly 414 | what our PerhapsInt does, but for any type. It's called Maybe. We'll get to that very shortly. 415 | 416 | \subsubsection{Newtype} 417 | 418 | \paragraph{} 419 | This is the last sort of type definition, and it is a bit less intuitive as to why you might want it. 420 | Basically, it's the same as a data declaration, except it's called \textbf{newtype} instead, and it 421 | can only contain one data constructor and one field. 422 | 423 | \begin{code} 424 | 425 | newtype HiddenInts = HiddenInts [Int] 426 | 427 | \end{code} 428 | 429 | \paragraph{} 430 | There are various reasons one might want to use a newtype declaration, but the most obvious is that, 431 | unlike a type synonym, it lets you control what people get to do with your new type. For instance, 432 | maybe you don't want to show people what's inside your list and you export that without the internal 433 | definition. Then, you can export whatever functions you want people to be able to act on it with and 434 | you have much more fine grained control over your data structure's invariants, even if internally all 435 | you use is something everyone can just pattern match over and take stuff out of. 436 | 437 | \subsection{Polymorphism and Type Classes} 438 | 439 | \subsubsection{Polymorphism} 440 | 441 | \paragraph{} 442 | There are some functions and data structures which don't just work for Int, Float, or Bool, but 443 | for everything in the same way. In a language like Java or C++, polymorphism is ad hoc, which means that 444 | in any given place, one has to instantiate your polymorphic type with a type, like Collection. 445 | In Haskell, the polymorphism is parametric, which means that you can use type variables in your function 446 | and data declarations. I'll display this below. 447 | 448 | \begin{code} 449 | 450 | theSame :: a -> a 451 | theSame x = x 452 | 453 | data Perhaps a = Indeed a | Alas 454 | 455 | \end{code} 456 | 457 | \paragraph{} 458 | Now we have a function theSame which takes something of any type a and returns whatever x you give it, 459 | and a type Perhaps a which is either Indeed an a or Alas, not an a. In the Prelude, theSame is called 460 | \textbf{id} and Perhaps is called \textbf{Maybe}, with data constructors \textbf{Just} and \textbf{Nothing}. 461 | 462 | \subsubsection{Typeclasses} 463 | 464 | \paragraph{} 465 | In object oriented programming, a class is basically a type with functions baked into it. An abstract 466 | class, or an interface, is a description of the sorts of functions you must bake into some type that 467 | inherits from it, extends it, what have you. A class in Haskell, referred to as a typeclass, is something 468 | more like an interface than anything else, but is an extension of this idea. We could take things from 469 | there, extending the concepts and keeping our past knowledge, but this is hardly creative. Let's try to 470 | discover some places where we might need them, given all of the tools we already have. 471 | 472 | \begin{code} 473 | 474 | containsAttempt :: [a] -> a -> Bool 475 | containsAttempt = undefined 476 | 477 | \end{code} 478 | 479 | \paragraph{} 480 | If we were to attempt to write this function, we'd immediately run into a problem... How do we check whether 481 | or not the a in our list is equal to the a we were given? We could use the == function we've been using 482 | in our earlier functions, but it turns out that actually is a function that belongs to a class called 483 | \textbf{Eq}. The way we can demand that our contains function only takes types that are an \textbf{instance} 484 | of Eq is shown below. 485 | 486 | \begin{code} 487 | 488 | contains :: (Eq a) => [a] -> a -> Bool 489 | contains [] _ = False -- No a is in the empty list 490 | contains (x:as) a 491 | | a == x = True 492 | | otherwise = contains as a 493 | 494 | \end{code} 495 | 496 | \paragraph{} 497 | Lets try to solve a harder problem, the problem of sorting a list. We need to have some notion of order to do 498 | this, and it turns out the concept of a total ordering is described in the class \textbf{Ord}. 499 | 500 | \begin{code} 501 | 502 | sortList :: (Ord o) => [o] -> [o] 503 | sortList [] = [] 504 | sortList (x:xs) = sortList [y | y <- xs, y < x] ++ (x : sortList [z | z <- xs, z <= x]) 505 | 506 | \end{code} 507 | 508 | \paragraph{} 509 | This introduced some new notation, just because I think this is so beautiful, but it's pretty intuitive. 510 | Basically, this is stating that the empty list is already sorted, and that if we have some element at 511 | the front of our list, we can recursively sort that list by taking all the elements that are less than the 512 | front element, sorting and putting them to the left, the front element in the middle, 513 | and all the elements greater than or equal to the front element to the right of it after sorting them. This 514 | is derived from a similar line of thought as quicksort, but doesn't have the same performance characteristics. 515 | In order to implement it for arbitrary lists, we need the \textbf{Constraint} Ord o, which is a sort of 516 | predicate that demands there must be a function for comparing things of type o. 517 | 518 | \paragraph{} 519 | That brings us a little closer to our definition, the idea that a class is a sort of requirement for a 520 | type, or a constraint. That's basically what we want when we have these sorts of desires for types which 521 | have certain qualities, a type which has a certain group of functions defined upon it in some way or 522 | another. This is similar to an interface, however an interface, at least in the languages which I've used 523 | them in, has the limitation that the first argument of each function specified must be the type which 524 | instantiated it. A class in Haskell, on the other hand, can even request that there exists a function 525 | that returns the type instantiating it. I'll now define our first class, and define one instance for it. 526 | 527 | \begin{code} 528 | 529 | class Testable t where 530 | test :: t -> Bool 531 | 532 | instance Testable Bool where 533 | test b = b 534 | 535 | \end{code} 536 | 537 | \paragraph{} 538 | The class declaration says that if t is Testable, there exists a function test which maps t to a Bool, 539 | presumably to True if the test was passed and to False if the test failed. The instance declaration says 540 | hey, if I have a Bool already, then testing it should be as simple as returning it. So for Bool, test 541 | is equivalent to id. We'll come back to this class later. 542 | 543 | \section{Data Structures} 544 | \paragraph{} 545 | Whenever I learn any new language, the first thing I make sure is that I'm able to implement basic data 546 | structures. I find that this increases my knowledge about the language and gives me confidence in 547 | implementing more complex things. As such, that's just what we'll do here. I've already showed you the built 548 | in list data structure, but we can implement something quite similar to it, something we'll call a Chain 549 | for now. We'll assume that a Link is a Chain, and each Link is attached to some Chain. 550 | 551 | \begin{code} 552 | 553 | data Chain a = Link a (Chain a) 554 | 555 | \end{code} 556 | 557 | \paragraph{} 558 | So now, whenever we have a Link a, we can pull out the first a, and we can get the rest of the chain. We 559 | can also imagine this function as one thing, similar to popping from a stack, where we get out the first 560 | element and the rest of the Chain. 561 | 562 | \begin{code} 563 | 564 | first :: Chain a -> a 565 | first (Link a _) = a 566 | 567 | rest :: Chain a -> Chain a 568 | rest (Link _ cs) = cs 569 | 570 | pop :: Chain a -> (a, Chain a) 571 | pop (Link a cs) = (a, cs) 572 | 573 | \end{code} 574 | 575 | \paragraph{} 576 | Cool, so now we have ways of taking things out of Chains, but how can we construct them? Well, in most 577 | programming languages, arguments to functions are evaluated strictly, so if some function call goes 578 | into an infinite loop, then your whole program halts. This is not the case with Haskell. In Haskell, 579 | items are evaluated lazily, which means that, until the result of some diverging computation is 580 | needed, it won't cause the program to halt. This lets us construct infinite chains via recursion, as 581 | below. 582 | 583 | \begin{code} 584 | 585 | forever :: a -> Chain a 586 | forever a = Link a (forever a) 587 | 588 | \end{code} 589 | 590 | \paragraph{} 591 | This is great, but all it really gives us is a way to create infinite constant sequences... Let's see 592 | what else we can do. Lets try to make some functions which complement the ones we already have. 593 | Particularly, we can look at pop, which takes a Chain and splits it into the rest and the first. Lets try 594 | to come up with the inverse of this function, which we can call push. 595 | 596 | \paragraph{} 597 | To do so, let's set some rules: push (pop c) = c and let's do some reasoning. 598 | 599 | \begin{quote} 600 | 601 | push (pop (Link a cs)) = push (a, cs) = Link a cs 602 | 603 | \end{quote} 604 | 605 | \paragraph{} 606 | From setting this identity and reasoning from there, we've come up with a definition for push which 607 | merely involves the parameters it needs to take. We can now define this. 608 | 609 | \begin{code} 610 | 611 | push (a, cs) = Link a cs 612 | 613 | \end{code} 614 | 615 | \paragraph{} 616 | What other functions should we try for? Well, what about a function which takes another function 617 | and maps every single element of our chain through it? In other words, if we have a Chain of 618 | all of the positive numbers, and we want to get all the even numbers, we can just pass our chain 619 | and the function that multiplies things by two through this mapping function. The axioms we'd want 620 | to satisfy for this function, which we'll call fmap, would probably be as follows: 621 | 622 | \begin{quote} 623 | 624 | fmap id x = x 625 | 626 | fmap f (fmap g x) = fmap (f . g) x 627 | 628 | \end{quote} 629 | 630 | \paragraph{} 631 | That is to say, if we map the identity function over our chains, we want them to stay the same, 632 | and if we map g and then map f over a chain, it should just be the same as doing g composed with f 633 | the first time. It turns out there is a typeclass for things of this exact form called Functor. 634 | Let's do some more reasoning and figure out how our fmap must be defined... 635 | 636 | 637 | \end{document} 638 | --------------------------------------------------------------------------------