├── README.md ├── tutorials ├── template.md ├── RecursionProblems.md ├── chapter4.md ├── chapter3.md ├── chapter2.md ├── chapter1.md └── chapter0.md └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # haskell-class 2 | Chapter notes and exercises from our weekly Haskell class. These notes roughly follow the print version of Miran Lipovača's excellent book [Learn You a Haskell](http://learnyouahaskell.com/). Please note that the chapters in the online version are off by one from the print version (e.g. Higher Order Functions is ch 6 rather that ch 5). 3 | -------------------------------------------------------------------------------- /tutorials/template.md: -------------------------------------------------------------------------------- 1 | # Creating a Tutorial 2 | 3 | This repository contains a template project for a DS12 tutorial or lab. Please use this as a reference when creating your own documentation, source code and sbt files. Note that `classname` should be one of: `scala`, `models` or `methods`. 4 | 5 | When creating your project you should make a README_ANSWERS first, then remove the answers and use the remainder as your README. You should also do this with your source code, i.e. create a directory hierarchy for your answers (`code/tutorialAnswers/src/main/scala/tutorialAnswers/lecture1`) and then strip the answers out and create a directory hierarchy for your skeleton code (`code/tutorial/src/main/scala/tutorial/lecture1`). Please reference the included tutorial for a concrete example. 6 | 7 | The project should (obviously) be distributed to residents without the answers. After they have had a chance to complete the tutorial you can re-distribute the entire project. 8 | 9 | Instructions throughout the tutorial should be written in clear, concise, and imperative language. 10 | 11 | The remainder of this README consists of general style conventions. 12 | 13 | ## Part 0 14 | 15 | Your project should be broken up into mulitple Parts. Use Part 0 to list the tutorial objectives. For example: 16 | 17 | In this tutorial we aim to review, define or explain 18 | 19 | * inheritance 20 | * Multiple inheritance and the "diamond problem" 21 | * composition / mix-ins 22 | * implicit conversions 23 | * type classes, and 24 | * implicit parameters 25 | 26 | 27 | ### Task (0a): Task Name 28 | 29 | A tutorial should have roughly ten Tasks (a few more or less is ok depending on Task difficulty), labs can have more. Each Task should have some deliverable source code (often in the form of a function implementation). Tasks in Part 0 should generally correspond to project setup or data acquisition. 30 | 31 | ### Task (0b): `functionName` 32 | 33 | A Part need not have Tasks, however each Task should have a descriptive name. The name could describe the problem, or refer to an unimplemented function in the source code. 34 | 35 | --- 36 | 37 | ## Part 1: [Useful Wikipedia/SO link](https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)) 38 | 39 | `code/tutorials/src/main/scala/tutorials/lecture3/Hierarchy.scala` 40 | 41 | ### (1a): Subsection 42 | 43 | You can optionally break out your Part into subsections like this. If you do then the subsections should correspond to the tasks with the same label (e.g. 1a). Also please note the reference to the corresponding `.scala` file above. 44 | 45 | ### Task (1a): Task Name 46 | 47 | This is a Task corresponding to the Subsection above. Please note that Tasks should be enumerated starting at `a` even if there is only one Task in a Part. 48 | 49 | ### (1b): Subsection 50 | 51 | If you do break your Part into Subsections, there should be at least two of them. 52 | 53 | --- 54 | 55 | ## Resources 56 | 57 | Include other relevant references (blog/SO posts, articles, books, etc) here. -------------------------------------------------------------------------------- /tutorials/RecursionProblems.md: -------------------------------------------------------------------------------- 1 | # Recursion Problems 2 | Here is a list of fun recursion problems. Try working through them in order, and feel free to use a function you wrote to solve an early problem to solve a later one. In fact, bonus points if you manage to do this! 3 | 4 | If you haven't already, take a look at the [Recursion chapter](https://github.com/DS12/haskell-class/blob/master/tutorials/chapter4.md) of these notes. That chapter explains recursion and walks you through some examples. 5 | 6 | Many of the functions in this document are implemented in Haskell already. When this is the case, the function you write will have `my-` added to its name. For example, there is a `length` function in Haskell, so you will name your function `myLength`. 7 | 8 | You should supply type signatures for all of these functions. Doing so will force you to clarify your thinking and will make writing the function body much easier. 9 | 10 | ## Part 0: `myLength` and `secondSmallest` 11 | 12 | ### (0a) 13 | Write a function called `myLength` that computes the length of a list. You should be able to get these results, for example: 14 | 15 | ``` 16 | Prelude> myLength [1,2,3,4,5] 17 | 5 18 | Prelude> myLength [] 19 | 0 20 | Prelude> myLength "cat" 21 | 3 22 | Prelude> myLength ["apple", "banana", "pear", "melon"] 23 | 4 24 | ``` 25 | 26 | ### (0b) 27 | Write a function called `secondSmallest` that finds the second smallest element in a list. (Hint: which of the functions you implemented in the Recursion chapter would be useful here?) 28 | 29 | ``` 30 | Prelude> secondSmallest [1,2,4,8,0] 31 | 1 32 | Prelude> secondSmallest [99,100,2] 33 | 99 34 | ``` 35 | 36 | ## Part 1: `mySum` and `myProduct` 37 | 38 | ### (1a) 39 | Write a function `mySum` that will compute the sum of a list of numbers. The sum of an empty list is `0` (why?). 40 | 41 | ### (1b) 42 | Write a function `myProduct` that will compute the product of a list of numbers. Hint: what is the product of an empty list? 43 | 44 | ``` 45 | Prelude> mySum [1,2,3,4] 46 | 10 47 | Prelude> myProduct [1,2,3,4] 48 | 24 49 | ``` 50 | 51 | ## Part 2: `myMap` and `myFilter` 52 | Here are two super popular functions. `myMap` allows you to do a transformation to every element of a list, and `myFilter` allows you to pick elements out of a list, based on some condition. 53 | 54 | ### (2a) 55 | Write a function called `myMap` that will take a function and a list and apply the function to every element of the list. The big challenge here will be in figuring out the type signature. 56 | 57 | ``` 58 | Prelude> myMap (\x -> x+1) [1,2,3] 59 | [2,3,4] 60 | Prelude> myMap myLength [[1,2,3,4], [1,2]] 61 | [4,2] 62 | ``` 63 | 64 | ### (2b) 65 | Write a function called `myFilter` that will throw out the elements of a list that do not satisfy some condition. 66 | 67 | ``` 68 | Prelude> myFilter (\x -> x > 0) [-1,-2,4,5] 69 | [4,5] 70 | Prelude> myFilter (/= 'a') "abcd" 71 | "bcd" 72 | ``` 73 | 74 | ## Part 3 75 | 76 | ### (3a) 77 | Write a function `myReverse` that reverses a list. 78 | 79 | ``` 80 | Prelude> myReverse "abcd" 81 | "dcba" 82 | Prelude> myReverse [1,3,5,9999] 83 | [9999,5,3,1] 84 | ``` 85 | 86 | ### (3b) 87 | A list is a _palindrome_ if it reads the same backwards as it does forwards. For example, `"stressed desserts"` is a palindrome. 88 | 89 | Write a function `isPalindrome` that returns `True` if its input is a palindrome and `False` if not. 90 | 91 | ``` 92 | Prelude> isPalindrome "stressed desserts" 93 | True 94 | Prelude> isPalindrome [1,2,3,2,1] 95 | True 96 | Prelude> isPalindrome [1,2,3,2] 97 | False 98 | ``` 99 | -------------------------------------------------------------------------------- /tutorials/chapter4.md: -------------------------------------------------------------------------------- 1 | # Chapter 4: Recursion 2 | 3 | ## Part 1 4 | In this tutorial we will talk about one of the most important concepts in functional programming: recursion. A function is _recursive_ if it defined in terms of itself. Here is a recursive function. 5 | 6 | ``` 7 | loop x = loop x 8 | ``` 9 | 10 | Obviously if we run this it will never actually do anything; it will just keep on calling itself forever. To avoid this, we often specify a _base case_ where the function does not call itself but instead takes some concrete value. In general, the base case should be the simplest possible input, and every time the function calls itself it should move closer to the base case. 11 | 12 | Here is an example using the Fibonacci sequence, which is one of the most famous sequences in mathematics. Even mathematically, it is defined recursively (there are non-recursive definitions as well but they are more complicated) as follows. The first two Fibonacci numbers are 0 and 1. From then on, each Fibonacci number is the sum of the previous two. 13 | 14 | So the sequence goes 0,1,1,2,3,5,8,13,... 15 | 16 | ``` 17 | fib :: Int -> Int 18 | fib 0 = 0 19 | fib 1 = 1 20 | fib n = fib (n-1) + fib (n-2) 21 | ``` 22 | 23 | Let's go through this function. The first line is the type declaration, which says that `fib` will take an integer as its input and spit one out as its output. The second and third lines are the base cases -- they tell `fib` what to do on the simplest and most basic inputs. The last line is the interesting one. It says that if we feed `fib` some value `n` that is not `0` or `1`, then it will take the two preceding Fibonacci numbers and add them up. 24 | 25 | ### (1a) 26 | What will you get if you call `fib 5`? Try to work it out in your head or on paper before running the code. 27 | 28 | ### (1b) 29 | What will you get if you call `fib (-2)`? Again, try to reason it out before running anything. 30 | 31 | --- 32 | 33 | One of the great things about recursion is that we can solve problems by answering two questions: 34 | 35 | * What is the simplest case of this problem? 36 | * How can we reduce a complex version of this problem to a simpler version? 37 | 38 | With Fibonacci, these questions were answered for us in the definition of the sequence. The simplest Fibonacci numbers to find are the first two, because we are told exactly what they are. To reduce the problem of finding `fib n`, we just have to look at `fib (n-1)` and `fib (n-2)`. 39 | 40 | ## Part 2 41 | 42 | Let's write a function that will take a list of integers and pull out the biggest one. For simplicity, let's say that the maximum of an empty list is `minBound`. 43 | 44 | ``` 45 | biggest :: [Int] -> Int 46 | ``` 47 | 48 | ### (2a) 49 | What is the simplest case of this problem? 50 | 51 | --- 52 | 53 | How do we simplify a complex case of the "biggest-finding" problem? With lists the first thing you should do is view the first element (or _head_) of the list as "special" and the rest of the list (or _tail_) as a "less complex" list to worry about. 54 | 55 | __Fact 1__: If the first element is bigger than the biggest element from the rest of the list, then our answer will just be the first element. 56 | 57 | __Fact 2__: If the first element is not the biggest, then our answer will be the biggest element from the rest of the list. 58 | 59 | Now all we have to do is convert the statements above into code. Here's how we do it. 60 | 61 | ``` 62 | biggest :: [Int] -> Int 63 | biggest [] = minBound 64 | biggest (x:xs) 65 | | x > (biggest xs) = x 66 | | otherwise = (biggest xs) 67 | ``` 68 | 69 | OK, the first line is the old type declaration. The second is the base case, since we defined the biggest element from an empty list to be `minBound` for this exercise. The third line is a pattern match. If the input isn't empty, we break it down in terms of its first element and its tail. 70 | 71 | The last two lines are just Fact 1 and Fact 2 translated into code. 72 | 73 | Note that we could also have used a `where` binding to avoid writing `biggest xs)` multiple times. 74 | 75 | ``` 76 | biggest :: [Int] -> Int 77 | biggest [] = minBound 78 | biggest (x:xs) 79 | | x > biggestFromTail = x 80 | | otherwise = biggestFromTail 81 | where biggestFromTail = biggest xs 82 | ``` 83 | 84 | In fact, `biggest` is already implemented for you in Haskell, though it is called `maximum`. 85 | 86 | ### (2b) 87 | Write a function `smallest :: [Int] -> Int` that computes the smallest number from a list. Let's define the smallest number in the empty list to be `maxBound`. 88 | 89 | ### (2c) 90 | Write a function `contains :: (Eq a) => a -> [a] -> Bool` that tests if an element lies in a list. For example: 91 | 92 | ``` 93 | Prelude> contains 2 [1,2,3] 94 | True 95 | Prelude> contains 2 [1,3,4,5] 96 | False 97 | Prelude> contains 'q' "Haskell is great" 98 | False 99 | ``` 100 | 101 | 102 | ## Part 3: Sorting 103 | Often you will have a list of things and will want to put them in order. This is called _sorting_. There are a variety of sorting algorithms, but we will discuss one in particular. Before going any further, let's remember an extremely useful bit of Haskell syntax: the _list comprehension_. 104 | 105 | Suppose I have a list `myList = [1,2,3,4,5]`, and I want to double its members, except for `5`. There are many ways of doing this, but one way is to tell Haskell exactly what you want, what you really really want. 106 | 107 | ``` 108 | Prelude> [2*x | x <- myList, x /= 5] 109 | [2,4,6,8,10] 110 | ``` 111 | 112 | All this means is "for every member `x` of `myList` that is not equal to `5`, give me `2*x`". 113 | 114 | Cool, so now we need to figure out how to sort a list. Thinking back to Part 1, let's try to answer these questions: 115 | 116 | * What is the simplest case of this problem? 117 | * How can we reduce a complex version of this problem to a simpler version? 118 | 119 | Hm, well the simplest list to sort is definitely the empty list, because there is no sorting to be done. The same goes for a list with only one element. 120 | 121 | The answer to the second question is actually pretty clever. Suppose we had the list `listToSort = [3,2,6,1,4,5]` and we wanted to put it in ascending order. As always, we'll match the pattern `(x:xs)`, so `x=3` and `xs = [2,6,1,4,5]`. 122 | 123 | The final answer will be `[1,2,3,4,5,6]`. Obviously the elements to the left of `3` are the ones that are less than `3` and the elements to right of `3` are the ones that are greater than `3`. So the problem of sorting `[3,2,6,1,4,5]` can be broken down into two simpler sorting problems. 124 | 125 | * Sort the stuff that is smaller than `3` 126 | * Sort the stuff that is bigger than `3` 127 | 128 | Then we take the former and stitch the latter to the end, with a `3` in the middle. 129 | 130 | ### (3a) 131 | Implement a function `sort :: (Ord a) => [a] -> [a]` that does this. 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /tutorials/chapter3.md: -------------------------------------------------------------------------------- 1 | # Syntax In Functions 2 | 3 | A big part of learning a language is figuring out how to write sentences in a way that other people can understand. Programming languages are the same way, except we need to be even more careful about adhering to the rules of the language. If I ask you "Where's the dog at?" you are smart enough to figure out that I really meant "Where is the dog?" and we can continue our conversation. 4 | 5 | Programming languages are not that smart, so we need to learn how to structure our programs in such a way that they can be understood. 6 | 7 | ## Part 1 : Pattern Matching 8 | 9 | The first syntactic construct we will look at is called __pattern matching__. Here's the idea: if we want a function to do different things depending on what its input looks like, all we have to do is specify how it will behave on different kinds or "patterns" of input. 10 | 11 | Here is a simple example from the book: 12 | 13 | ``` 14 | lucky :: (Integral a) => a -> String 15 | lucky 7 = "LUCKY NUMBER SEVEN!" 16 | lucky x = "Sorry, you're out of luck pal!" 17 | ``` 18 | 19 | Let's run through what this is doing. 20 | 21 | * The first line is the type declaration, which says that `lucky` takes an `Integral` value as an input and outputs a `String`. 22 | * The second line says that if the input looks like `7`, the output will be `"LUCKY NUMBER SEVEN!"`. The next line won't matter at all -- we take the first thing we can get. 23 | * The last line says that if the input is `x` (which could be anything, since we don't use that variable anywhere else in this function), the output will be `"Sorry, you're out of luck pal!"`. The pattern `x` acts as a catch-all here -- `x` is a totally generic pattern that can match any input. 24 | 25 | OK, so what happens if we call `lucky 7` in real life? Well, `7` is an integer, so the types check out on line 1. On line two Haskell checks to see if the input `7` looks like the pattern `7`. Cool, we have a pattern match! Now Haskell looks at the second part of line two, the bit after the equals sign. We get that bit as our output. Here's what it looks like in ghci: 26 | 27 | ``` 28 | *Main> lucky 7 29 | "LUCKY NUMBER SEVEN!" 30 | 31 | *> Main lucky 99 32 | "Sorry, you're out of luck, pal!" 33 | ``` 34 | 35 | ### Task (1a) 36 | Write a function called `snape :: String -> String` that does the following: 37 | 38 | * If the input is `"Harry"`, output `"Shut up, Potter"` 39 | * If the input is `"Ron"`, output `"Shut up, Weasley"` 40 | * If the input is `"Hermione"`, output `"Shut up, Granger"` 41 | * Otherwise, output `"Shut up"` 42 | 43 | ----- 44 | 45 | One common use of pattern matching is working with lists. You may remember that Haskell lets us use the `Cons` operator (otherwise known as `(:)`) to add as element to the front of a list. In fact, `[1,2,3]` is just a prettier way of writing `1 : (2 : (3 : []))` or `1 : [2,3]`. 46 | 47 | Take a look at this pattern: `x:xs`. What sort of lists follow this pattern? That is, what sort of lists can we write as some element `x` tacked onto the front of some other list `xs` 48 | 49 | Well, `[1,2,3]` does, because we can write it like `1 : [2,3]`. In fact, any list with at least one element follows this pattern, because we can make `x` its first element and `xs` everything after the first element. 50 | 51 | By the same logic, the pattern `x:y:rest` can match any list with at least two elements. `x` will match with the first element, `y` will match with the second, and `rest` will match with the rest of the list. You can even write a pattern that will match with any list with at least 100 elements if you really want to. 52 | 53 | ### Task (1b) 54 | If you define 55 | 56 | ``` 57 | pickElement :: [a] -> a 58 | pickElement (x:y:z:rest) = z 59 | ``` 60 | 61 | What will happen if you call the following? 62 | 63 | * `pickElement [1,2,3,4,5]`? 64 | * `pickElement ["Moony", "Wormtail", "Padfoot", "Prongs"]` 65 | * `pickElement [1..]` (this is the infinite list of positive integers). 66 | 67 | Try to figure it out, then try it for yourself. 68 | 69 | ----- 70 | 71 | Note that if we call `pickElement ` on an empty list, we get in trouble: 72 | 73 | ``` 74 | *Main> pickElement [] 75 | *** Exception: :6:5-32: Non-exhaustive patterns in function 76 | pickElement 77 | ``` 78 | 79 | This happens because the empty list doesn't match the pattern we used the define the function. The patterns were "non-exhaustive" because we didn't tell the function what to do with an input with fewer than 3 elements. 80 | 81 | ## Part 2: Guards 82 | Suppose you wanted to write a function `chooseRestaurant :: Int -> String` that would take the Yelp rating of the restaurant as an input and output a string detailing how excited you are to eat there, according to these guidelines: 83 | 84 | * If the rating is 5, output `"Super-duper excited!!!"` 85 | * If the rating is 4, output `"Somewhat hyped."` 86 | * Otherwise, output `"No. Please no."` 87 | 88 | You could do this with pattern-matching (assuming that ratings only go from 1 to 5) 89 | 90 | ``` 91 | chooseRestaurant :: Int -> String 92 | chooseRestaurant 5 = "Super-duper excited!!!" 93 | chooseRestaurant 4 = "Somewhat hyped." 94 | chooseRestaurant 3 = "No. Please no." 95 | chooseRestaurant 2 = "No. Please no." 96 | chooseRestaurant 1 = "No. Please no." 97 | ``` 98 | 99 | Great, problem solved. But imagine if ratings could go from 1 to 100 or something. Then we'd have to type out 100 lines, each with a different pattern. In the words of numerous infomercials, __"There HAS to be a better way!"__ 100 | 101 | There is, and it's called a Guard. Rather than looking for patterns in our input, we can decide what to output based on properties of our input. For example, the property of being less than or equal to three, in the example above. 102 | 103 | Here's the Guard version of `chooseRestaurant`: 104 | 105 | ``` 106 | chooseRestaurant :: Int -> String 107 | chooseRestaurant rating 108 | | rating <= 3 = "No. Please no." 109 | | rating == 4 = "Somewhat hyped" 110 | | rating == 5 = "Super-duper excited!!!" 111 | ``` 112 | 113 | Nice, much better. 114 | 115 | ### Task (2a) 116 | Using guards, write a function called `comicBookGuy :: Int -> String` that takes a movie rating to the phrase Comic Book Guy (from The Simpsons -- please someone get this) probably said when he first saw it. That is, if the input is `5` the output should be `"Best. Movie. Ever."` and if the input is less than `5` the output should be `"Worst. Movie. Ever."` 117 | 118 | ----- 119 | 120 | One useful keyword is `otherwise`, which simply catches any input that doesn't meet the criteria for the guards that come before it. For example, if we were worried that restaurants could have ratings above `5` on Yelp and wanted to output `"No, that rating is suspicious"` for those restaurants, we could have written `chooseRestaurant` like this: 121 | 122 | ``` 123 | chooseRestaurant :: Int -> String 124 | chooseRestaurant rating 125 | | rating <= 3 = "No. Please no." 126 | | rating == 4 = "Somewhat hyped" 127 | | rating == 5 = "Super-duper excited!!!" 128 | | otherwise = "No, that rating is suspicious." 129 | ``` 130 | 131 | ### Task (2b) 132 | Using `otherwise`, change the definition of `comicBookGuy` to output `"OMG that movie was amazing. omgomgomg"` if the rating is not less than five or equal to 5. 133 | 134 | ## Part 3 : Where 135 | 136 | Let's write a simple function that will tell us if the square of an integer is less than 10, between 10 and 19, between 20 and 29, or larger than 29. 137 | 138 | ``` 139 | squareSize :: Int -> String 140 | squareSize n 141 | | n*n < 10 = "Less than ten" 142 | | n*n < 20 = "Between ten and nineteen" 143 | | n*n < 30 = "Between twenty and twenty-nine" 144 | | otherwise = "Even larger than twenty-nine" 145 | ``` 146 | 147 | OK, that will work, but we had to type `n*n` four times: three times in the function and another to complain about it afterwards. So-called "where bindings" let us avoid all this: 148 | 149 | ``` 150 | squareSize :: Int -> String 151 | squareSize n 152 | | square < 10 = "Less than ten" 153 | | square < 20 = "Between ten and nineteen" 154 | | square < 30 = "Between twenty and twenty-nine" 155 | | otherwise = "Even larger than twenty-nine" 156 | where square = n*n 157 | ``` 158 | 159 | The only difference is that we added a `where` at the end, creating a value called `square`. Then we replaced all the `n*n`s in our original function with `square`, and got a much more readable function. 160 | 161 | ### Task (3a) 162 | Write a function called `quintSize` that does the same thing as `squareSize`, but using the fifth power of its input rather than the square. 163 | -------------------------------------------------------------------------------- /tutorials/chapter2.md: -------------------------------------------------------------------------------- 1 | # Types and Typeclasses 2 | 3 | ## Types 4 | 5 | As you've seen briefly, there are many different kinds of data we interact with when writing programs. You've already 6 | seen `Integer`s like the numbers 1,2,3,4 ; `String`s like the series of characters `"hello world"` ; as well as lists 7 | like the collection of numbers `[1,2,3,4]`. Another common kind is a `Float` which represents a number with decimals (for example, 1.2345). These different kinds of data referred to as different "types". By thinking about the type of our 8 | data, we can catch mistakes before we actually execute our code. And whether we like to admit it 9 | or not, we are always dealing with types (even when the language doesn't make it explicit) because we make implicit 10 | assumptions in our code. For example: 11 | 12 | ```haskell 13 | div a b = a / b 14 | ``` 15 | 16 | This simple function assumes that it makes sense to divide the first argument by the second. However, that is not 17 | always the case. What do you think would happen if we divided one string by another? Let's make the REPL tell us. 18 | Fire up the console by executing `ghci` in your terminal and execute the following line: 19 | 20 | ```haskell 21 | Prelude > "hello" / "world" 22 | ``` 23 | 24 | You should see the following error message: 25 | 26 | No instance for (Fractional [Char]) arising from a use of ‘/’ 27 | In the expression: "asdf" / "asdf" 28 | In an equation for ‘it’: it = "asdf" / "asdf" 29 | 30 | As you would have expected, we get an error telling us that we cannot divide one string by another. And even though 31 | we **could** rely on our awesome programming skills to ensure we never pass two strings to our `div` function, it would 32 | be nice if we could get a warning if we ever made such a mistake. Luckily, Haskell (as well as many other languages) 33 | lets us make these assumptions in what is called the "type signature" of a function. 34 | 35 | Expressing the type signature of a function takes just a small line above our function definition: 36 | 37 | ```haskell 38 | div :: Int -> Int -> Float 39 | div a b = a / b 40 | ``` 41 | 42 | The first line is usually read "the function `div` is a takes two `Int`s and returns a `Float`". Question: Why does `div` 43 | have to return a `Float` instead of an `Int`? If you're stumped, think about the answer to `3 / 2`. 44 | 45 | A more generic function would probably take two `Float`s instead of `Int`s but you get the idea. 46 | 47 | Also, it is helpful to know that you can always check the type signature of a function (and 48 | basically everything else) in the REPL by starting the statement with `:t`: 49 | 50 | ```haskell 51 | Prelude > :t "Hello" 52 | "hello" :: [Char] 53 | ``` 54 | 55 | ### Type variables 56 | 57 | Some type signatures are not "concrete". That is to say, the types of certain data structures 58 | are defined in terms of some parameter. For example, since you can have a list of integers 59 | as well as one of strings, the type of a list is denoted by `[a]` where `a` stands for any 60 | type. To illustrate this point, consider `["hello", "world"]`. This element has the type 61 | `[String]` (meaning a list of strings), whereas `[1,2,3]` has the type `[Int]`. 62 | 63 | Function type signatures can also be generic in the same sense. Take for example, `head` 64 | which returns the first element in a list. What do you think the type signature would be? Let's 65 | find out! 66 | 67 | ```haskell 68 | Prelude > :t head 69 | head :: [a] -> a 70 | ``` 71 | 72 | That means that head takes a list of `a` and returns a single `a`. 73 | 74 | ## Typeclasses 75 | 76 | 77 | A typeclass is a sort of interface that defines some behavior. If a type is a part of a typeclass, that means that it supports and implements the behavior the typeclass describes. Take the equality function for example: 78 | 79 | ``` 80 | ghci> :t (==) 81 | (==) :: (Eq a) => a -> a -> Bool 82 | ``` 83 | 84 | Everything before the `=>` symbol is called a class constraint. We can read the previous type declaration like this: the equality function takes any two values that are of the same type and returns a Bool. The type of those two values must be a member of the Eq class (this was the class constraint). 85 | 86 | The `Eq` typeclass provides an interface for testing for equality. Any type where it makes sense to test for equality between two values of that type should be a member of the Eq class. All standard Haskell types except for `IO` (the type for dealing with input and output) and functions are a part of the `Eq` typeclass. 87 | 88 | Typeclasses allow us to generalize over a set of types in order to define and execute a standard set of features for those types. For example, the ability to test values for equality is useful, and we’d want to be able to use that function for data of various types. In fact, we can test any data that has a type that implements the typeclass known as Eq for equality. We do not need separate equality functions for each different type of data; as long as our datatype implements, or instantiates, the Eq typeclass, we can use the standard functions. 89 | 90 | Philip Wadler famously described this tension between types and functions as the [Expression Problem](https://en.wikipedia.org/wiki/Expression_problem) 91 | 92 | >The expression problem is a new name for an old problem. The goal is to define a datatype by cases, where one can add new cases to the datatype and new functions over the datatype, without recompiling existing code, and while retaining static type safety (e.g., no casts). 93 | 94 | Typeclasses and types in Haskell are, in a sense, opposites. Where a declaration of a type defines how that type in 95 | particular is created, a declaration of a typeclass defines how a set of types are consumed or used in computations. 96 | This tension is related to the expression problem which is about defining code in terms of how data is created or 97 | processed. 98 | 99 | This chapter explains some important predefined typeclasses, only some of which have to do with numbers, as well as 100 | going into more detail about how typeclasses work more generally. 101 | 102 | 103 | ## Part 1: `Eq` 104 | 105 | ### Task (1a): Getting type information 106 | 107 | Use the GHCi command `:info` to query information about the following types: `Bool`, `Double`, `Int` and `Integer`. 108 | 109 | What typeclasses does `Double` implement that `Int` doesn't? 110 | 111 | What typeclasses does `Int` implement that `Integer` doesn't? 112 | 113 | What does this tell you about the differences between `Double`, `Int` and `Integer` numerically? 114 | 115 | The information includes the data declaration for the type in question. In your REPL, it also tells you where the datatype and its instances are defined for the compiler. Next we see a list of instances. Each of these instances is a typeclass that the type in question implements, and the instances are the unique specifications of how the type makes use of the methods from that typeclass. 116 | 117 | ### Task (1b): Getting typeclass information 118 | 119 | Now use `:info` to query information about the following _typeclasses_:`Eq` and `Ord`. 120 | 121 | What are the basic functions specified in each typeclass? What might they do? 122 | 123 | How does the returned information differ from above? 124 | 125 | What is the relationship between types, functions, and typeclasses? 126 | 127 | You can use a search engine like [Hoogle](http://haskell.org/hoogle) to find information on Haskell datatypes and typeclasses. This is useful for looking up what the deal is with things like `Fractional`. 128 | 129 | Hoogle is a Haskell API search engine, which allows you to search many standard Haskell libraries by function name or type signature. This becomes very useful as you become more fluent in Haskell types as you will be able to input the type of the function you want and find the functions that match. 130 | 131 | ### Task (1c): `==` 132 | 133 | What is the type signature of the `==` function in `Eq`? 134 | 135 | What do you think would happen to the `a` if we partially apply it to a string, like so `(==) "cat"`? Test your hypothesis with the `:t` command. 136 | 137 | Were you correct? What happened to the `(==) :: Eq a` part? Why? 138 | 139 | What would happen if we apply `==` to two cats: `"cat1" == "cat2"`? 140 | 141 | What would happen if the first two arguments `a` and `a` to `==` aren’t the same type? 142 | 143 | Remember: the type of `a` is usually set by the le most instance of it and can’t change in the signature `Eq a => a -> a -> Bool`. Applying `(==)` to Integer will bind the `a` type variable to `Integer`. 144 | 145 | --- 146 | 147 | ## Part 2: Numerical Typeclasses 148 | 149 | `Num` is a typeclass implemented by most numeric types. As we see when we query the information, it has a set of predefined functions, like `Eq`: 150 | 151 | ### Task (2b): `Num` and `Integral` 152 | 153 | Use GHCi to look up the functions defined in the `Num` and `Integral` typeclasses. 154 | 155 | What do you think the functions in `Num` are for? Use Hoogle to look up any you're unsure of. 156 | 157 | `(Real a, Enum a) => Integral a` is a _typeclass constraint_. It means that any type that implements `Integral` must already have instances for Real and `Enum` typeclasses. An integral type must be both a real number and enumerable (more on `Enum` later) and therefore may employ the methods each of those typeclasses. In turn, the `Real` typeclass itself requires an instance of `Num`. So, the Integral typeclass may put the methods of `Real` and `Num` into effect (in addition to those of `Enum`). 158 | 159 | Since `Real` cannot override the methods of `Num`, this typeclass inheritance is only additive and the ambiguity problems caused by multiple inheritance in some programming languages — the so-called “deadly diamond of death” — are avoided. 160 | 161 | ### Task (2b): Tuple Experiment 162 | 163 | Look at the types given for `quotRem` and `divMod`. What do you think those functions do? Test your hypotheses by playing with them in the REPL. We’ve given you a sample to start with below: 164 | 165 | ``` 166 | let ones x = snd (divMod x 2) 167 | ``` 168 | 169 | ### Task (2c): Parts of a Whole 170 | 171 | `quotRem` and `divMod` are actually combined versions of 4 separate functions: `quot` ,`rem`,`div` and `mod`. Let's examine them individually. 172 | 173 | What do the following two functions do and why? 174 | 175 | ``` 176 | let id1 x y = (x `quot` y)*y + (x `rem` y) 177 | let id2 x y = (x `div` y)*y + (x `mod` y) 178 | ``` 179 | Do certain inputs cause them to break? Why? 180 | 181 | One example where the differences would matter is testing if an integer is even or odd. 182 | 183 | ``` 184 | let buggyOdd x = x `rem` 2 == 1 185 | buggyOdd 1 // True 186 | buggyOdd (-1) // False (wrong!) 187 | 188 | let odd x = x `mod` 2 == 1 189 | odd 1 // True 190 | odd (-1) // True 191 | ``` 192 | 193 | What is happening here? 194 | 195 | ### Task (2d): Digging Deeper 196 | 197 | At a glance you might think that `quotRem` and `divMod` are the same. Try them on these arguments: 198 | 199 | ``` 200 | divMod (-12) 5 201 | quotRem (-12) 5 202 | ``` 203 | 204 | How do the results differ? 205 | 206 | Haskell's `div` follows the convention of mathematicians (or at least number theorists) in always truncating down division (towards negative infinity not 0) so that the remainder is always nonnegative. 207 | 208 | ### Task (2d): Can Haz Deeper 209 | 210 | Now try 211 | 212 | ``` 213 | divMod (-12) 5 214 | divMod 12 (-5) 215 | ``` 216 | 217 | How do the results differ? 218 | 219 | Note that both `quotRem` and `divMod` satisfy `(q,r) == divMod x y` if and only if `x == q*y + r`. 220 | 221 | --- 222 | 223 | ## Resources 224 | 225 | Include other relevant references (blog/SO posts, articles, books, etc) here. 226 | -------------------------------------------------------------------------------- /tutorials/chapter1.md: -------------------------------------------------------------------------------- 1 | # Getting Started in Haskell 2 | 3 | ## Part 1: Expressions 4 | 5 | ## Part 2: Functions 6 | 7 | ### Anonymous Functions 8 | 9 | Function literal syntax is a bit different in Haskell than in Scala. In Scala, we'd write `(h,t) => ...`, in Haskell, we write `\h t -> ...`. The parameters to a lambda function mirrors the syntax for named function application (see below), with parameters separated by spaces. Following the parameter list is the `->`, then the body of the lambda. So, for example: 10 | 11 | ``` 12 | Prelude> (\x -> 2*x) 10 13 | 20 14 | ``` 15 | 16 | I can also get type information about anonymous functions (indeed about pretty much anything in Haskell), by using the `:type` or `:t` command like so: 17 | 18 | ``` 19 | Prelude> :t (\x -> 2*x) 20 | (\x -> 2*x) :: Num a => a -> a 21 | ``` 22 | 23 | Note that function types are written using `->` instead of `=>` as in Scala. 24 | 25 | 26 | 27 | ### Task (2a): Functions Eating Functions 28 | 29 | In Haskell functions are [first class objects](https://en.wikipedia.org/wiki/First-class_function), which means we can pass functions to functions just as easily as we can pass other data types. Make a lambda function that eats another function and applies it to the value 2, then feed it the lambda `(\y -> y + 2)`. What result do you get? 30 | 31 | Now use the `:t` command on your first lambda, what kind of type is it? 32 | 33 | This snippet shows a few new things. Let's start by looking at the type signature. What's with all the `->` symbols? Functions in Haskell are curried by default. Although we can write `(Int,Int) -> Int`, for the type of a function that expects a pair of integers and returns an `Int`, we almost always work with curried functions in Haskell and the language has special support for interpreting curried function application efficiently. The `->` operator is right-associative, so for example the type `(a -> b -> b) -> b -> List a -> b` can be read the same way you'd read the Scala signature: 34 | 35 | ```Scala 36 | def foldRight[A,B](f: (A,B) => B, z: B, xs: List[A]): B 37 | ``` 38 | 39 | Note also that unlike Scala, Haskell does not have a distinction between `val`, `def`, `lazy val`, and `var` (data are immutable and lazily evaluated). All declarations use the same syntax, a symbol name, followed by any arguments or patterns, followed by an `=` sign, followed by the body of the definition. 40 | 41 | ### Task (2b): Partial Application 42 | 43 | Make a lambda function that adds two numbers together and apply it to the values 5 and 10 as above. Experiment with using the `:t` command on the lambda when applied to both, one, or no arguments respectively. In the last case the resulting type should be `Num a => a -> a -> a`, which is similar but not quite equal to what you had in Task (2b). Any ideas why? 44 | 45 | 46 | ### Task (2c): Googling Errors 47 | 48 | If you enter your lambda function from above into GHCi without any arguments, you should get an error that looks something like this: 49 | 50 | ``` 51 | No instance for (Show (a0 -> a0 -> a0)) (maybe you haven't applied enough arguments to a function?) 52 | ``` 53 | 54 | WTF? Never fear, this is an opportunity to participate in the time-honored programming tradition known as 'Googling your error'. When I Googled the first part of that error (without the suggestion), my top hit was the following link: 55 | 56 | http://stackoverflow.com/questions/18615666/no-instance-for-show-a0-arising-from-a-use-of-print-the-type-variable-a0-i 57 | 58 | That's somewhat useful (& you should definitely make friends with SO, a fun place to start is with the [Zalgo post](http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags)), however the answer is over-specific. We can help ourselves by removing the (rather specific) type information from our error message. Try Googling `No instance for Show` instead. You should get a wider variety of results including [this one](http://users.jyu.fi/~sapekiis/haskell-pitfalls/#no-instance-for-show), which tells us that we need to define the show function from the Show type class. We'll discuss type classes next week. 59 | 60 | 61 | ### Named Functions 62 | 63 | Lambdas are great, but at some point you have to start giving functions names. Here are two equivalent ways to do that: 64 | 65 | ``` 66 | inc = \x -> x+1 67 | ``` 68 | or 69 | 70 | ``` 71 | inc x = x+1 72 | ``` 73 | 74 | The syntax for function application is simple juxtaposition, with arguments separated by spaces, as in `go n 1` (vs `go(n, 1)` in Scala). Function application is left-associative and binds tighter than any other operation, so `f x y+1` would actually be parsed as `(f x y) + 1`, and we can use parentheses to obtain a desired grouping. 75 | 76 | 77 | ``` 78 | factorial 0 = 1 79 | factorial n = n * factorial (n-1) 80 | ``` 81 | 82 | This example demonstrates some simple pattern matching in Haskell, matching on the numeric literal `0`. We can write a function's name several times, supplying a pattern for each argument. Patterns are matched top to bottom, as in Scala. We'll talk more about Haskell's pattern matching in the next section. 83 | 84 | You can optionally preface a funtion with its type signature like so: 85 | 86 | ``` 87 | factorial :: Int -> Int 88 | factorial 0 = 1 89 | factorial n = n * factorial (n-1) 90 | ``` 91 | 92 | This is not required, but it is considered good form when writing actual programs. 93 | 94 | ### Task (2d): Functions in the REPL 95 | 96 | You can put `factorial` into a file and compile it like we did with our HelloWorld function, but let's try to define it directly in the REPL. 97 | 98 | You can define multi-line functions in the REPL by using the `let` keyword and braces like so: 99 | 100 | ``` 101 | let { factorial 0 = 1 ; factorial n = n * factorial (n-1) } 102 | ``` 103 | 104 | Try that and then make sure `factorial 3` gives the result you'd expect (i.e. 6). Now lets try a [second way](http://stackoverflow.com/questions/2846050/how-to-define-a-function-in-ghci-across-multiple-lines): 105 | 106 | ``` 107 | Prelude> :{ 108 | Prelude| let factorial 0 = 1 109 | Prelude| factorial n = n * factorial (n-1) 110 | Prelude| :} 111 | Prelude> factorial 3 112 | 6 113 | ``` 114 | 115 | Do this yourself. If you're not careful you may get an error like this: `:156:3: parse error on input ‘where’`. That's because, like Python, Haskell is sensitive to white-space. Basically that means that Haskell determines where blocks begin and end based on indentation. Certain keywords (like `let` and `where`) introduce a _layout block_. Check out the [following link](https://en.wikibooks.org/wiki/Haskell/Indentation) to get the hang of how to indent code properly. 116 | 117 | 118 | ### Where and Let 119 | 120 | Let's look at a couple of other definitions for the factorial function: 121 | 122 | ```Haskell 123 | factorial' :: Int -> Int 124 | factorial' n = go n 1 125 | where go 0 acc = acc 126 | go n acc = go (n-1) (n * acc) 127 | 128 | factorial'' :: Int -> Int 129 | factorial'' n = 130 | let go 0 acc = acc 131 | go n acc = go (n-1) (n * acc) 132 | in go n 1 133 | ``` 134 | 135 | A few things about this code: 136 | * Identifier names in Haskell can contain the `'` symbol (as well as `_`, letters, and numbers, though data types must start with a capital letter and other identifiers cannot start with a number or `'`). 137 | * We are also making use of a local function to write our loop in both `factorial'` and `factorial''`, much like we'd do in Scala, though unlike Scala, _all tail calls are optimized_. Syntactically, we can place local definition(s) _after_ the expression that references it, using a `where`-clause (used in `factorial'`) or we can place the local definitions _before_ the expression referencing it, using a `let` expression (used in `factorial''`). 138 | 139 | ### Task (2e): Tail Recursion (Optional) 140 | 141 | `factorial` and `factorial'` are both recursive, but only `factorial'` is [tail recursive](https://en.wikipedia.org/wiki/Tail_call). Why? 142 | 143 | ### Task (2f): Fibonacci 144 | 145 | Using the `factorial` code above as a model, write a function `fibonacci` that computes the nth [Fibonacci number](https://en.wikipedia.org/wiki/Fibonacci_number): 146 | 147 | ``` 148 | Prelude> map fibonacci [0..10] 149 | [1,1,2,3,5,8,13,21,34,55,89] 150 | ``` 151 | 152 | ## Part 3: Lists and Strings 153 | 154 | Lists are probably the most used data structure in Haskell. In this section we'll look at the basics of lists, strings (which are lists) and list comprehensions. 155 | 156 | https://wiki.haskell.org/Cookbook/Lists_and_strings 157 | 158 | ### Lists 159 | 160 | A list is a homogenous data structure. It stores several elements of the same type. That means that we can have a list of integers or a list of characters but we can't have a list that has a few integers and then a few characters. We can write list literals using the syntax `[1,2,3,4]`, `["a","b"]`. 161 | 162 | Lists in Haskell come built in and have some special syntax. We write the type `List Int` as `[Int]`, we write `Nil` as `[]`, and `Cons h t` as `h:t`. 163 | 164 | ### Task (3a): WTF is Cons? 165 | 166 | Anytime you are not sure what something is in Haskell, check out its type: 167 | 168 | ``` 169 | :t (:) 170 | ``` 171 | 172 | Now that you know the two things it eats, try feeding it two of those things and see what it spits out. What does `:` do? 173 | 174 | 175 | ### Task (3a): Heads and Tails 176 | 177 | Two more commonly used list functions are `head` and `tail`. Test these out and then combine them to make a function `foo` that gets the second element of a list like so: 178 | 179 | ``` 180 | Prelude> foo [1,2,3,4] 181 | 2 182 | Prelude> foo "Yoyoyo" 183 | 'o' 184 | ``` 185 | 186 | ### Strings 187 | 188 | As we just saw, a string is simply a list of characters. 189 | 190 | ``` 191 | Prelude> 'i' : [] 192 | "i" 193 | Prelude> 'h' : "i" 194 | "hi" 195 | Prelude> head "They alive, dammit!" 196 | 'T' 197 | ``` 198 | 199 | ### Task (3b): Hoogle it 200 | 201 | A great tool for finding haskell functions is [Hoogle](https://www.haskell.org/hoogle/), which allows you to search by type signature among other things. Get the type of `foo` and enter it into Hoogle. What other functions have that same type? 202 | 203 | ### Ranges 204 | 205 | One handy way to make a list is using ranges: 206 | 207 | ``` 208 | Prelude> [1..10] 209 | [1,2,3,4,5,6,7,8,9,10] 210 | Prelude> ['a' .. 'z'] 211 | "abcdefghijklmnopqrstuvwxyz" 212 | ``` 213 | 214 | You can also specify steps implicitly like so: 215 | 216 | ``` 217 | Prelude> [1,3 .. 10] 218 | [1,3,5,7,9] 219 | ``` 220 | 221 | ### List Comprehensions 222 | 223 | The pattern of chaining operations is so useful in Haskell that it has its own operator `>>=` (called bind). It is equivalent to `flatMap` in Scala. 224 | 225 | ```Haskell 226 | [1..10] >>= (\x -> if odd x then [x*2] else []) 227 | ``` 228 | 229 | ### Task (3c): Repeat the odd numbers in a List 230 | 231 | Use the bind operator and a lambda to repeat the odd numbers in a List. So the list `[1..10]` should generate the list `[1,1,2,3,3,4,5,5,6,7,7,8,9,9,10]` 232 | 233 | The examples above use things called monads, which are like computation builders. The common theme is that the monad chains operations in some specific, useful way. In the list comprehension, the operations are chained such that if an operation returns a list, then the following operations are performed on every item in the list. 234 | 235 | ### Task (3c): Functional IO 236 | 237 | Bind does a number of interesting things in Haskell. Try running the following line of code in your REPL: 238 | 239 | ```Haskell 240 | putStrLn "What is your name?" >>= (\_ -> getLine) >>= (\name -> putStrLn ("Welcome, " ++ name ++ "!")) 241 | ``` 242 | What happens? 243 | 244 | This is an example of the bind operator for the IO monad. The IO monad performs the operations sequentially, but passes a "hidden variable" along, which represents "the state of the world", which allows us to write I/O code in a pure functional manner. 245 | 246 | 247 | ### "Infinite" Data Structures 248 | 249 | One advantage of the non-strict nature of Haskell is that data constructors are non-strict, too. This should not be surprising, since constructors are really just a special kind of function (the distinguishing feature being that they can be used in pattern matching). For example, the constructor for lists, (:), is non-strict. 250 | 251 | Non-strict constructors permit the definition of (conceptually) infinite data structures. Here is an infinite list of ones: 252 | 253 | ``` 254 | ones = 1 : ones 255 | ``` 256 | 257 | Perhaps more interesting is the function numsFrom: 258 | 259 | numsFrom n = n : numsFrom (n+1) 260 | 261 | Thus numsFrom n is the infinite list of successive integers beginning with n. From it we can construct an infinite list of squares: 262 | 263 | ``` 264 | squares = map (^2) (numsfrom 0) 265 | ``` 266 | 267 | (Note the use of a section; ^ is the infix exponentiation operator.) 268 | 269 | Of course, eventually we expect to extract some finite portion of the list for actual computation, and there are lots of predefined functions in Haskell that do this sort of thing: take, takeWhile, filter, and others. The definition of Haskell includes a large set of built-in functions and types---this is called the "Standard Prelude". The complete Standard Prelude is included in Appendix A of the Haskell report; see the portion named PreludeList for many useful functions involving lists. For example, take removes the first n elements from a list: 270 | 271 | ``` 272 | take 5 squares => [0,1,4,9,16] 273 | ``` 274 | 275 | The definition of ones above is an example of a circular list. In most circumstances laziness has an important impact on efficiency, since an implementation can be expected to implement the list as a true circular structure, thus saving space. 276 | 277 | For another example of the use of circularity, the Fibonacci sequence can be computed efficiently as the following infinite sequence: 278 | 279 | ``` 280 | fib = 1 : 1 : [ a+b | (a,b) <- zip fib (tail fib) ] 281 | ``` 282 | 283 | where zip is a Standard Prelude function that returns the pairwise interleaving of its two list arguments: 284 | 285 | ``` 286 | zip (x:xs) (y:ys) = (x,y) : zip xs ys 287 | zip xs ys = [] 288 | ``` 289 | 290 | Note how fib, an infinite list, is defined in terms of itself, as if it were "chasing its tail." 291 | 292 | --- 293 | 294 | ## Resources 295 | 296 | Include other relevant references (blog/SO posts, articles, books, etc) here. -------------------------------------------------------------------------------- /tutorials/chapter0.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | [Haskell](http://www.haskell.org/haskellwiki/Haskell) is a purely functional language. Unlike Scala, there is no escape hatch--if you want to write imperative code in Haskell, you are forced to use the the IO and ST monads, and/or a higher-level library built atop these data types (technically, Haskell does include some functions, like unsafePerformIO, that allow you to subvert its purity. But these functions are used extremely rarely, as they don't mix well with Haskell's laziness.) This lack of escape hatch has been one reason why many discoveries of how to write functional programs have come from the Haskell community--in Haskell, the question, "how do I express this program using pure functions?" is not merely an intellectual exercise, it is a prerequisite to getting anything done! 4 | 5 | Haskell is in many ways a nicer language for functional programming than Scala, and if you are serious about learning more FP, we recommend learning it. We recommend this even if you continue to program predominantly in Scala. 6 | 7 | ## Part 0: Environment Setup 8 | 9 | First things first. Lets all make sure we have Haskell installed and we have a decent text editor. To get Haskell we will use [Homebrew](http://brew.sh/), which is a package manager for OSX. Check to 10 | 11 | 12 | ### Task (0a): Install Homebrew 13 | 14 | Check to see whether you have Homebrew installed by opening up a Terminal (`/Applications/Utilities/Terminal.app/`) and enter the following code: 15 | 16 | `which brew` 17 | 18 | If you get back the pathname `/usr/local/bin/brew` then you are good to go. Otherwise you do not have Homebrew installed. Never fear though it's a cinch to set up, just enter the following into your Terminal: 19 | 20 | `/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"` 21 | 22 | A tutorial should have roughly ten Tasks (a few more or less is ok depending on Task difficulty), labs can have more. Each Task should have some deliverable source code (often in the form of a function implementation). Tasks in Part 0 should generally correspond to project setup or data acquisition. 23 | 24 | ### Task (0b): Install GHC 25 | 26 | With Homebrew installed, getting Haskell is a piece of cake, simply enter the following into your Terminal: 27 | 28 | `brew install ghc` 29 | 30 | GHC stands for ['Glasgow Haskell Compiler'](https://wiki.haskell.org/GHC). The 'Glasgow' comes from the fact that GHC was originally written by Kevin Hammond in 1989 at the University of Glasgow. A compiler is a computer program (actually a set of programs) that transforms source code written in a programming language (the source language) into another computer language (the target language), with the latter often having a binary form known as object code. The most common reason for converting source code is to create an executable program. GHC is an open source native code compiler for Haskell, and it is [itself written in Haskell](https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler). If this sounds weird that's because it is. Compilers are cool. 31 | 32 | ### Task (0b): Fire up GHCi 33 | 34 | One of the programs that comes with GHC is the interpreter GHCi. An interpreter (sometimes called a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop)) is an interactive computer programming environment that takes inputs, evaluates them, and returns the result in a call-and-reponse fashion very much like a [Unix shell](https://en.wikipedia.org/wiki/Unix_shell) (which is what your Terminal actually is). 35 | 36 | Start GHCi by simply typing `ghci` into your shell. You should see a prompt similar to the one below. 37 | 38 | ``` 39 | cem3394$ ghci 40 | GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help 41 | ``` 42 | 43 | Take the tip and have a look at the help menu: 44 | 45 | ``` 46 | Prelude> :? 47 | Commands available from the prompt: 48 | 49 | evaluate/run 50 | : repeat last command 51 | :{\n ..lines.. \n:}\n multiline command 52 | :add [*] ... add module(s) to the current target set 53 | :browse[!] [[*]] display the names defined by module 54 | (!: more details; *: all top-level names) 55 | :cd change directory to 56 | :cmd run the commands returned by ::IO String 57 | :complete [] list completions for partial input string 58 | :ctags[!] [] create tags file for Vi (default: "tags") 59 | (!: use regex instead of line number) 60 | :def define command : (later defined command has 61 | precedence, :: is always a builtin command) 62 | :edit edit file 63 | :edit edit last module 64 | :etags [] create tags file for Emacs (default: "TAGS") 65 | :help, :? display this list of commands 66 | :info[!] [ ...] display information about the given names 67 | (!: do not filter instances) 68 | :issafe [] display safe haskell information of module 69 | :kind[!] show the kind of 70 | (!: also print the normalised type) 71 | :load [*] ... load module(s) and their dependents 72 | :main [ ...] run the main function with the given arguments 73 | :module [+/-] [*] ... set the context for expression evaluation 74 | :quit exit GHCi 75 | :reload reload the current module set 76 | :run function [ ...] run the function with the given arguments 77 | :script run the script 78 | :type show the type of 79 | :undef undefine user-defined command : 80 | :! run the shell command 81 | 82 | -- Commands for debugging: 83 | 84 | :abandon at a breakpoint, abandon current computation 85 | :back go back in the history (after :trace) 86 | :break [] [] set a breakpoint at the specified location 87 | :break set a breakpoint on the specified function 88 | :continue resume after a breakpoint 89 | :delete delete the specified breakpoint 90 | :delete * delete all breakpoints 91 | :force print , forcing unevaluated parts 92 | :forward go forward in the history (after :back) 93 | :history [] after :trace, show the execution history 94 | :list show the source code around current breakpoint 95 | :list show the source code for 96 | :list [] show the source code around line number 97 | :print [ ...] show a value without forcing its computation 98 | :sprint [ ...] simplified version of :print 99 | :step single-step after stopping at a breakpoint 100 | :step single-step into 101 | :steplocal single-step within the current top-level binding 102 | :stepmodule single-step restricted to the current module 103 | :trace trace after stopping at a breakpoint 104 | :trace evaluate with tracing on (see :history) 105 | 106 | -- Commands for changing settings: 107 | 108 | :set