• Stars
    star
    437
  • Rank 99,659 (Top 2 %)
  • Language
    Haskell
  • Created over 6 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Fork of the original Data61 course to be more Stack friendly

Functional Programming Course

Haskell logo

Written by Tony Morris & Mark Hibberd for Data61

With contributions from individuals (thanks!)

This version is maintained by Chris Allen at https://github.com/bitemyapp/fp-course

Introduction

The course is structured according to a linear progression and uses the Haskell programming language to learn programming concepts pertaining to functional programming.

Exercises are annotated with a comment containing the word "Exercise." The existing code compiles, however answers have been replaced with a call to the Haskell error function and so the code will throw an exception if it is run. Some exercises contain tips, which are annotated with a preceding "Tip:". It is not necessary to adhere to tips. Tips are provided for potential guidance, which may be discarded if you prefer a different path to a solution.

The exercises are designed in a way that requires personal guidance, so if you attempt it on your own and feel a little lost, this is normal. All the instructions are not contained herein.

Differences from the Original

  • We officially support the stack build tool.
  • The test suite is converted from tasty to Hspec.

The original course is located here.

Getting Help

There are two mailing lists for asking questions. All questions are welcome, however, your first post might be moderated. This is simply to prevent spam.

  1. #haskell-beginners on Freenode is an IRC channel that is operated by Chris Allen. The participants are volunteers and fellow learners who help others on their own time.

  2. #haskell or #haskell-beginners on the FPChat Slack. FPChat is a Slack community of fellow travelers. The #haskell and #haskell-beginners channels are good places to seek assistance with this course.

Getting Started

  1. Install Stack which will manage your compiler versions automatically and enable you to build this project.

  2. Change to the directory containing this document.

  3. Execute the command make ghci, which will compile and load all the source code. You may need to set permissions on the root directory and the ghci configuration file, chmod go-w .ghci ./.

  4. Inspect the introductory modules to get a feel for Haskell's syntax, then move on to the exercises starting with Course.Optional. The Progression section of this document lists the recommended order in which to attempt the exercises.

  5. Edit a source file to a proposed solution to an exercise. At the ghci prompt, issue the command :reload. This will compile your solution and reload it in the GHC interpreter. You may use :r for short.

Tips after having started

  1. Some questions take a particular form. These are called WTF questions. WTF questions are those of this form or similar:
  • What does ____ mean?
  • What does the ____ function mean?
  • What is a ____ ?
  • Where did ____ come from ?
  • What is the structure of ____ ?

They are all answerable with the :info command. For example, suppose you have the question, "What does the swiggletwoop function mean?" You may answer this at GHCi with:

> :info swiggletwoop

You may also use :i for short.

  1. Functional Programming techniques rely heavily on types. This reliance may feel foreign at first, however, it is an important part of this course. If you wish to know the type of an expression or value, use :type. For example,

    > :type reverse

    List t -> List t

    This tells you that the reverse function takes a list of elements of some arbitrary type (t) and returns a list of elements of that same type. Try it.

    You may also use :t for short.

  2. GHCi has TAB-completion. For example you might type the following:

    > :type rev

    Now hit the TAB key. If there is only one function in scope that begins with the characters rev, then that name will auto-complete. Try it. This completion is context-sensitive. For example, it doesn't make sense to ask for the type of a data type itself, so data type names will not auto-complete in that context, however, if you ask for :info, then they are included in that context. Be aware of this when you use auto-complete.

    This also works for file names:

    > readFile "/etc/pas"

    Now hit the TAB key. If there is only one existing filename on a path that begins with /etc/pas, then that name will auto-complete. Try it.

    If there is more than one identifier that can complete, hit TAB twice quickly. This will present you with your options to complete.

  3. Follow the types.

    You may find yourself in a position of being unsure how to proceed for a given exercise. You are encouraged to adopt a different perspective. Instead of asking how to proceed, ask how you might proceed while adhering to the guideline provided by the types for the exercise at hand.

    It is possible to follow the types without achieving the desired goal, however, this is reasonably unlikely at the start. As you become more reliant on following the types, you will develop more trust in the potential paths that they can take you, including identification of false paths.

    Your instructor must guide you where types fall short, but you should also take the first step. Do it.

  4. Do not use tab characters

    Set up your text editor to use space characters rather than tabs. Using tab characters in Haskell can lead to confusing error messages. GHC will give you a warning if your program contains a tab character.

Running the tests

Tests are available as a tasty test suite.

Hspec

Hspec tests are stored under the test/ directory. Each module from the course that has tests has a corresponding <MODULE>Spec.hs file. Within each test module, tests for each function are grouped using the describe function. Within each test group there are test cases (it function), and properties (prop function).

To run the full test suite, build the project as follows:

> stack test

Tasty will also allow you to run only those tests whose description match a pattern. Tests are organised in nested groups named after the relevant module and function, so pattern matching should be intuitive. For example, to run the tests for the List module you could run:

> stack test --ta "--match=Course.List/"

Likewise, to run only the tests for the headOr function in the List module, you could use:

> stack test --ta "--match=Course.List/headOr"

In addition, GHCi may be used to run tasty tests. Assuming you have run ghci from the root of the project, you may do the following:

# Ensure you've run `make test` at least once!
make test-ghci

From there you can run :main at your GHCi prompt to run the entire test suite. If you want to do the equivalent of stack test --ta "--match=ListSpec" in GHCi do this:

:main --match=Course.List/

Similarly you can run:

:main --match=Course.List/headOr

To target just the Course.List/headOr tests. If you've changed your code, run :r to reload and then run your :main invocation again.

Progression

It is recommended to perform some exercises before others. The first step is to inspect the introduction modules.

  • Course.ExactlyOne
  • Course.Validation

They contain examples of data structures and Haskell syntax. They do not contain exercises and exist to provide a cursory examination of Haskell syntax. The next step is to complete the exercises in Course.Optional.

After this, the following progression of modules is recommended:

  • Course.List
  • Course.Functor
  • Course.Applicative
  • Course.Monad
  • Course.FileIO
  • Course.State
  • Course.StateT
  • Course.Extend
  • Course.Comonad
  • Course.Compose
  • Course.Traversable
  • Course.ListZipper
  • Course.Parser (see also Course.Person for the parsing rules)
  • Course.MoreParser
  • Course.JsonParser
  • Course.Interactive
  • Course.Anagrams
  • Course.FastAnagrams
  • Course.Cheque

During this progression, it is often the case that some exercises are abandoned due to time constraints and the benefit of completing some exercises over others. For example, in the progression, Course.Functor to Course.Monad, the exercises repeat a similar theme. Instead, a participant may wish to do different exercises, such as Course.Parser. In this case, the remaining answers are filled out, so that progress on to Course.Parser can begin (which depends on correct answers up to Course.Monad). It is recommended to take this deviation if it is felt that there is more reward in doing so.

After these are completed, complete the exercises in the projects directory.

IDEs

The use of IDEs (integrated development environments) is not recommended as many Haskell beginners will spin their wheels trying to get the tools installed and working.

Instead, if you'd like maximum interactivity and fast feedback the following is recommended:

  • A regular text editor which can syntax highlight and indent Haskell source code. Sublime Text, Emacs, vim, Atom, and Visual Studio Code are all suitable for this purpose.

  • A GHCi REPL created with make ghci or make test-ghci.

  • For automatic type errors, use ghcid. To install ghcid run make dev-deps and then to run ghcid use: make ghcid. When ghcid is ready to go, it should look something like:

All good (27 modules)

From there you should be able to edit a source file, save, and see ghcid reload and type-check your code automatically.

Introducing Haskell

This section is a guide for the instructor to introduce Haskell syntax. Each of these points should be covered before attempting the exercises.

  • values, assignment
  • type signatures :: reads as has the type
    • The -> in a type signature is right-associative
  • functions are values
  • functions take arguments
    • functions take only one argument but we approximate without spoken language
    • functions can be declared inline using lambda expressions
    • the \ symbol in a lambda expression denotes a Greek lambda
  • operators, beginning with non-alpha character, are in infix position by default
    • use in prefix position by surrounding with (parentheses)
  • regular identifiers, beginning with alpha character, are in prefix position by default
    • use in infix position by surrounding with backticks
  • polymorphism
    • type variables always start with a lower-case character
  • data types, declared using the data keyword
    • following the data keyword is the data type name
    • following the data type name are zero of more type variables
    • then = sign
    • data types have zero or more constructors
      • data type constructors start with an upper-case character, or colon (:)
    • following each constructor is a list of zero or more constructor arguments
    • between each constructor is a pipe symbol (|)
    • the deriving keyword gives us default implementations for some functions on that data type
    • when constructors appear on the left side of = we are pattern-matching
    • when constructors appear on the right side of = we are constructing
  • type-classes

Learning the tools

When this course is run in-person, some tools, particularly within Haskell, are covered first.

  • GHCi
    • :type
    • :info
    • :load:
    • :reload
    • :main
  • values
  • type signatures
    • x :: T is read as x is of the type T
  • functions are values
  • functions take arguments
  • functions take one argument
  • lambda expressions
  • operators (infix/prefix)
    • identifiers starting with isAlpha are prefix by default, infix surrounded in backticks (`)
    • other identifiers are infix by default, prefix surrounded in parentheses
  • data types
    • data keyword
    • recursive data types
  • pattern matching
  • deriving keyword
  • type-classes
  • type parameters
    • always lower-case 'a'..'z'
    • aka generics, templates C++, parametric polymorphism
  • running the tests
    • cabal test

Parser grammar assistance

The exercises in Parser.hs can be assisted by stating problems in a specific way, with a conversion to code.

English Parser library
and then bindParser >>=
always valueParser pure
or |||
0 or many list
1 or many list1
is is
exactly n thisMany n
fail failed
call it x \x ->

Monad comprehension

do-notation
  • insert the word do
  • turn >>= into <-
  • delete ->
  • delete \
  • swap each side of <-
LINQ
  • write from on each line
  • turn >>= into in
  • delete ->
  • delete \
  • swap each side of in
  • turn value into select

Demonstrate IO maintains referential transparency

Are these two programs, the same program?

p1 ::
  IO ()
p1 =
  let file = "/tmp/file"
  in  do  _ <- writeFile file "abcdef"
          x <- readFile file
          _ <- putStrLn x
          _ <- writeFile file "ghijkl"
          y <- readFile file
          putStrLn (show (x, y))

p2 ::
  IO ()
p2 =
  let file = "/tmp/file"
      expr = readFile file
  in  do  _ <- writeFile file "abcdef"
          x <- expr
          _ <- putStrLn x
          _ <- writeFile file "ghijkl"
          y <- expr
          putStrLn (show (x, y))

What about these two programs?

def writeFile(filename, contents):
    with open(filename, "w") as f:
    f.write(contents)

def readFile(filename):
    contents = ""
    with open(filename, "r") as f:
    contents = f.read()
    return contents

def p1():
    file = "/tmp/file"

    writeFile(file, "abcdef")
    x = readFile(file)
    print(x)
    writeFile(file, "ghijkl")
    y = readFile(file)
    print (x + y)

def p2():
    file = "/tmp/file"
    expr = readFile(file)

    writeFile(file, "abcdef")
    x = expr
    print(x)
    writeFile(file, "ghijkl")
    y = expr
    print (x + y)

One-day

Sometimes this course material is condensed into one-day. In these cases, the following exercises are recommended:

  • Optional
    • mapOptional
    • bindOptional
    • (??)
    • (<+>)
  • List
    • headOr
    • product
    • length
    • map
    • filter
    • (++)
    • flatMap
    • reverse
  • Functor
    • instance Functor List
    • instance Functor Optional
    • instance Functor ((->) t)
    • instance Functor void
  • Applicative
    • instance Applicative List
    • instance Applicative Optional
    • instance Applicative ((->) t)
    • lift2
    • sequence
  • FileIO

References

More Repositories

1

learnhaskell

Learn Haskell
Makefile
7,847
star
2

bloodhound

Haskell Elasticsearch client and query DSL
Haskell
419
star
3

esqueleto

New home of Esqueleto, please file issues so we can get things caught up!
Haskell
371
star
4

dotfiles

My .emacs, .screenrc, etc.
Emacs Lisp
149
star
5

revise

RethinkDB client for Clojure
Clojure
146
star
6

brambling

Datomic schema and data migration library/toolkit
Clojure
69
star
7

blackwater

Clojure SQL query logging
Clojure
56
star
8

open-haskell

Community edited and directed course based on Spring '13 cis194.
Haskell
46
star
9

blacktip

Haskell clone of Boundary's k-ordered unique id service
Haskell
40
star
10

papers

29
star
11

brotli2-rs

Brotli encoders/decoers for Rust
Rust
28
star
12

presentations

what it says on the tin
Haskell
24
star
13

hedgehog-checkers

Like the checkers library, but for hedgehog. Common stuff you'd want to check.
Haskell
22
star
14

makefiles

I use Makefile as a sort of command dispatcher/secondary memory, this is a repo of the common ones I keep reusing
17
star
15

trajectile

Tracing library for Clojure
Clojure
13
star
16

ledgertheory

Coq
13
star
17

boxcar-willie

Tomatoes or something
Rust
13
star
18

neubite

http://www.bitemyapp.com
JavaScript
11
star
19

lefortovo

Π±Π΅Π·Π³Ρ€Π°ΠΌΠΎΡ‚Π½Ρ‹ΠΉ gitignore and makefile fetcher in Rust
Rust
11
star
20

clojure-template-benchmarks

Needed proper benchmarking of frontend views
Clojure
11
star
21

bulwark

Throttling / IP banning library for Ring-compatible Clojure apps based on Kickstarter's Rack::attack
Clojure
11
star
22

monad-transformers-step-by-step

Haskell
10
star
23

bluetick

SQL DSL
Haskell
10
star
24

hacker-type-emacs

Hacker typer for Emacs
Emacs Lisp
10
star
25

buttress

Messing around
Haskell
9
star
26

shawty-prime

url shortener
Haskell
9
star
27

duke

Elasticsearch client and query DSL for Rust, based on Bloodhound
Rust
8
star
28

teef

Hakyll project for my website.
Haskell
8
star
29

studyhaskell

Study Haskell in a group setting
6
star
30

bedrock

A Yesodian foundation
Haskell
6
star
31

haskell-wishlist

Libraries wishlist / project ideas / learning opportunities
6
star
32

emojicon-bootstrap

emojicons scrape and curated database for dash expander
Python
5
star
33

persistent-activerecord-ecto

Haskell
5
star
34

my-limes

How am I going to hold onto all these mutuals, Rust edition
Rust
5
star
35

Pijul

Copy
OCaml
5
star
36

yesod-template-project

Haskell
5
star
37

shiftrss

Rust clone of https://siftrss.com/
Rust
5
star
38

lambdadelta

Imageboard software written in Haskell
Haskell
4
star
39

shawty

Tiny URL shortener web app made with Haskell, Scotty, Hedis (Redis)
Haskell
4
star
40

ghc-gc-tune

Haskell
4
star
41

styles

Stylish themes for various websites I've modified.
CSS
4
star
42

doc-workshop

Little project for automatically rebuilding documents as you save them and work on them.
Haskell
3
star
43

haskell-jwt

JWT thingy, not mine.
Haskell
3
star
44

sendgrid-haskell

Haskell client for sending email via SendGrid's API
Haskell
3
star
45

hagglers

Haskell Kaggle Project
3
star
46

monohaskell

sssshhhh
CSS
3
star
47

netwire

Real repo at: darcs get http://hub.darcs.net/ertes/netwire
Haskell
3
star
48

entr

Not mine, this is a mirror of https://bitbucket.org/eradman/entr/
C
3
star
49

github-dark-theme

my modification of the original dark userstyle to make it more readable
3
star
50

cis194-fall16

Haskell
2
star
51

furp

Every kid wants a Furpy
Haskell
2
star
52

csvtest

Haskell
2
star
53

aws-tools

Collection of tools for AWS automations
Haskell
2
star
54

polyparse

Archived from the darcs repo
Haskell
2
star
55

chat

chat
Haskell
2
star
56

grom

grom eats your Clojure code
Haskell
2
star
57

geesthacht

DynamoDB client for Haskell
Haskell
2
star
58

simon-speck-rs

Currently buggy attempt at a SIMON implementation in Rust
Rust
2
star
59

Scroot

Django auditing app for the lazy
Python
2
star
60

hpp

A Haskell Pre-Processor
Haskell
2
star
61

strong-types-and-testing

Haskell
2
star
62

hsnippet

Original is located at: https://bitbucket.org/mightybyte/hsnippet/
Haskell
2
star
63

openbusiness

contracts, etc.
2
star
64

freki

A Haskell AI suite for playing Warmachine
Haskell
2
star
65

knob

A Toggl client for posting time entries
Rust
2
star
66

timesheet-csv-example

Haskell CSV processing example
Haskell
2
star
67

whostalkin

whostalkin
Haskell
2
star
68

opvault

1Password library in Haskell
Haskell
2
star
69

ipython

same as the original, but ignores lines with #PDBNULL in them.
Python
1
star
70

stm-chans

Mirror of http://community.haskell.org/~wren/stm-chans/
Haskell
1
star
71

hickey

A git-backed wiki written in Haskell.
Haskell
1
star
72

esqueleto-select-source-error-misuse

Reproducing https://github.com/bitemyapp/esqueleto/issues/29
Haskell
1
star
73

hips

Haskell
1
star
74

hst

Automatically exported from code.google.com/p/hst
Haskell
1
star
75

exference-exference-core

Haskell
1
star
76

diwali

Little toy problem, ignore it if I haven't pointed you here
Haskell
1
star
77

example-haskell-mailer

Haskell
1
star
78

thodol

it's a wiki
JavaScript
1
star
79

plow-email

An email surver! Hooray!
Haskell
1
star
80

bluster

Tiny Clojure utility belt for SwaggerUI (http://swagger.wordnik.com/)
Clojure
1
star
81

haizod

An IRC bot on a Raspberry Pi 2
Haskell
1
star
82

luatex-arabic-example

TeX
1
star
83

Luna

The Luna Programming Language
Haskell
1
star
84

break-unagi-chan

This isn't really a "fault" in unagi-chan, I'm misusing it here.
Haskell
1
star
85

bushfire

Terminal Twitter client
Haskell
1
star
86

prelim

Better Prelude
Haskell
1
star
87

broadcast-bench

Haskell
1
star
88

rebase_example

Haskell
1
star
89

hhh

Messing around with Servant
Haskell
1
star
90

panic-repro-initTc-unsolved-constraints

Haskell
1
star
91

pinbin

Haskell
1
star
92

exference-exference

Haskell
1
star
93

Pasterip

Rips content from Pastebin, not originally mine.
Python
1
star
94

j

J Programming language source
C
1
star
95

tf-idf-1

Document ranking using tf-idf
Python
1
star
96

garrulous

chat server yo
Haskell
1
star
97

scratch

Scratch space for ideas, lessons, etc
Haskell
1
star
98

nt-in-haskell

Not mine, this is Compall's shindig - https://gitorious.org/nt-in-haskell
Haskell
1
star
99

piebot

Haskell
1
star
100

bluepencil

DraftJS raw content representation -> HTML. _Not_ licensed free or open source software.
Haskell
1
star