2017-08-07 06:21:51 +03:00
|
|
|
Advanced FP Course
|
|
|
|
=====================
|
|
|
|
|
|
|
|
You
|
|
|
|
---
|
|
|
|
|
|
|
|
* Have completed, or are capable of completing, the [Data61 FP Course](https://github.com/data61/fp-course)
|
|
|
|
* Have a few months self-study to your name
|
|
|
|
* Want to know how to build larger applications with statically typed FP
|
|
|
|
* Are willing to accept that a web application is a sufficient choice
|
|
|
|
|
|
|
|
We
|
|
|
|
--
|
|
|
|
|
|
|
|
* Have constructed a sequence of goals of increasing difficulty
|
|
|
|
* Have provided a framework within which to apply these goals
|
|
|
|
* Have included relevant components of larger applications:
|
|
|
|
- Package dependencies
|
|
|
|
- Project configuration
|
|
|
|
- Application testing & building
|
2017-08-07 09:23:32 +03:00
|
|
|
- Encoding / Decoding messages (JSON & Binary)
|
2017-08-07 06:21:51 +03:00
|
|
|
- Persistent storage integration
|
|
|
|
- App state & configuration management
|
|
|
|
- Error handling & reporting
|
|
|
|
* Will utilise both type & test driven development techniques
|
|
|
|
* Will explain architectural and design trade-offs when appropriate
|
|
|
|
|
2017-08-09 06:06:21 +03:00
|
|
|
|
|
|
|
Tonys simpler version:
|
|
|
|
---
|
|
|
|
|
2017-08-17 09:48:54 +03:00
|
|
|
NB : No doctests yet :(
|
|
|
|
|
2017-08-09 06:06:21 +03:00
|
|
|
- Simplest web app - LEVEL 01
|
|
|
|
- with shared state (RPS game) -- Not awesome, maybe just do config (readerT) instead.
|
|
|
|
- with JSON/aeson
|
|
|
|
- with testing (hedgehog and friends)
|
|
|
|
- lenses and refactoring possibilities
|
|
|
|
- with database layer (postgresql-simple | sqlite)
|
|
|
|
|
2017-08-10 09:25:08 +03:00
|
|
|
* Level 01 : Simple Hello World web app.
|
|
|
|
* Level 02 : Define our application spec with types!
|
|
|
|
* Level 03 : Add some flexible configuration
|
2017-08-11 08:54:21 +03:00
|
|
|
* Level 04 : Testing & Tools (hspec & ghcid)
|
2017-08-10 09:25:08 +03:00
|
|
|
* Level 05 : Database layer (postgresql-simple)
|
|
|
|
* Level 06 : ReaderT & Refactoring
|
2017-08-17 09:48:54 +03:00
|
|
|
-- Working on this one...
|
2017-08-10 09:25:08 +03:00
|
|
|
* Level 07 : ExceptT & Refactoring
|
2017-08-17 09:48:54 +03:00
|
|
|
|
|
|
|
-- NEXT...
|
2017-08-10 09:25:08 +03:00
|
|
|
* Level 08 : (Bonus Round) Lenses & Refactoring
|
|
|
|
|
2017-08-17 09:48:54 +03:00
|
|
|
-- Unsure...
|
|
|
|
* Level 09 : Add Sessions (handwave?), so I can have some semblance of application state so I can add some property based tests?
|
|
|
|
|
|
|
|
TODO:
|
|
|
|
* Teacher notes/guide
|
|
|
|
* Second branch with stubbed out code for students to use
|
|
|
|
* Answer branch with working code
|
|
|
|
|
2017-08-09 06:06:21 +03:00
|
|
|
Below is Sean going nuts for things
|
|
|
|
---
|
|
|
|
|
2017-08-07 10:14:29 +03:00
|
|
|
UNSURE:
|
|
|
|
===
|
|
|
|
|
|
|
|
Use of lenses and classy `mtl` will be left to supplemental material. I would
|
|
|
|
like to be able to use it lenses more but the additional explanation required
|
|
|
|
might be a bit much and not very predictable ?
|
|
|
|
|
2017-08-07 06:21:51 +03:00
|
|
|
Ultimate Goal
|
|
|
|
===============
|
|
|
|
|
|
|
|
This course aims to teach some of the techniques for building a larger
|
|
|
|
application with FP, using Haskell. By the end of this course you should be
|
|
|
|
comfortable tackling more advanced projects, and expanding on the concepts and
|
|
|
|
choices presented here in your own future efforts.
|
|
|
|
|
|
|
|
We will build an ultra basic web application and build upon it.
|
|
|
|
|
2017-08-07 09:23:32 +03:00
|
|
|
Subgoals (?)
|
|
|
|
========
|
|
|
|
- ghcid
|
|
|
|
- hedgehog
|
|
|
|
- cabal files
|
2017-08-07 06:21:51 +03:00
|
|
|
|
2017-08-07 09:23:32 +03:00
|
|
|
Goals
|
|
|
|
======
|
|
|
|
|
|
|
|
1 - Death to Strings
|
|
|
|
---
|
|
|
|
Start up and Servant introduction.
|
|
|
|
|
2017-08-07 09:26:56 +03:00
|
|
|
* Use Scotty/Warp for the "hello, world" application.
|
|
|
|
* Explain that we're using strings for routes and this is bad(TM).
|
|
|
|
* Move to Servant, explain why, show type driven dev to explain routes->function relationship.
|
2017-08-07 09:23:32 +03:00
|
|
|
|
|
|
|
2 - Faking Global Vars with Science
|
|
|
|
---
|
|
|
|
Show that nothing can be changed in the current app without recompliation.
|
|
|
|
Rework the application so we can change the port values and have general app
|
|
|
|
config.
|
|
|
|
|
2017-08-07 09:26:56 +03:00
|
|
|
* Read a file in app start up to allow for port config changes.
|
|
|
|
* Explain that this can be cumbersome to explicitly pass the config around, there are better ways(TM).
|
|
|
|
* Add `mtl` dependency.
|
2017-08-07 10:14:29 +03:00
|
|
|
* Natural Transformation required from our new `ReaderT` to Servant (too much?).
|
2017-08-07 09:23:32 +03:00
|
|
|
|
|
|
|
3 - Would you like to play a game?
|
|
|
|
---
|
|
|
|
Introduce handling input/output also preempt the inclusion of persistent storage.
|
|
|
|
|
2017-08-07 09:26:56 +03:00
|
|
|
* Add rock-paper-scissors data type. (Don't create Enc/Dec instances yet)
|
|
|
|
* Add route to accept an RPS move that always plays paper against the user.
|
|
|
|
* Go over what the errors from Servant & GHC are telling us.
|
|
|
|
* Add the required instances.
|
|
|
|
* Change the function up so that it randomly selects a move, evaluates victory/defeat.
|
2017-08-07 09:23:32 +03:00
|
|
|
|
|
|
|
4 - Type safe tantrums
|
|
|
|
---
|
|
|
|
Introduce error handling by breaking REST rules by having our application throw
|
|
|
|
an error when it loses at Rock-Paper-Scissors.
|
|
|
|
|
2017-08-07 09:26:56 +03:00
|
|
|
* Change RPS function to throw an error on defeat, creating required error data types.
|
|
|
|
* Discuss the errors that appear RE return values and making Servant respond appropriately.
|
2017-08-07 10:14:29 +03:00
|
|
|
* Introduce `ExceptT`, change the `ReaderT` from earlier to what we want it to be.
|
|
|
|
* More discussion to be had here regarding the ordering of transformer stacks.
|
2017-08-07 09:26:56 +03:00
|
|
|
* Discuss the errors that appear. Work through fixing these with type-holes in the Natural Transform.
|
2017-08-07 09:23:32 +03:00
|
|
|
|
|
|
|
5 - Elephants
|
|
|
|
---
|
|
|
|
We'd like to be able to store a history of RPS games.
|
|
|
|
|
2017-08-07 10:14:29 +03:00
|
|
|
* Create a datatype that has some game info, respective moves, outcome, time.
|
|
|
|
* Introduce and integrate `postgresql-simple`:
|
|
|
|
* Config for connection
|
|
|
|
* `Connection` on the `ReaderT`
|
|
|
|
* Using `Connection` from `ReaderT` in `query` function(s)
|
|
|
|
* Add the required instances so we can read/write our datatype (provide a SQL file to initialise/purify the DB)
|
2017-08-08 02:45:19 +03:00
|
|
|
* Add our route to the API to request games by id, demonstrate work flow of 'game not found'.
|
2017-08-07 10:14:29 +03:00
|
|
|
* Work through the errors using type-holes to create our function.
|
|
|
|
* Stringly queries acceptable for now - postgresql-simple
|
2017-08-07 09:23:32 +03:00
|
|
|
|
2017-08-07 10:14:29 +03:00
|
|
|
** Prompt discussion about what lurks beneath the surface of the `IO a` query functionality.
|
2017-08-07 09:23:32 +03:00
|
|
|
|
2017-08-07 10:14:29 +03:00
|
|
|
6 - Except when exceptionally excepted
|
|
|
|
---
|
|
|
|
Handling, catching, and rethrowing exceptions. Motivate errors as values over exceptions.
|
|
|
|
|
|
|
|
* Possible ways postgresql-simple can fail on us, note that the types provide no information
|
|
|
|
* Introduce exception handling with `catching` and `handling` to our error values.
|
|
|
|
* Generalise our current DB querying technique so that we take a query and
|
|
|
|
handle some exceptional cases.
|
|
|
|
* Discuss the relevance of handling these errors:
|
|
|
|
* Shouldn't they just come up in testing?
|
|
|
|
* I'm sure there are other points here, some Haskell applications are built
|
|
|
|
not to care about these sorts of errors.
|
|
|
|
|
2017-08-09 06:06:21 +03:00
|
|
|
* Discuss how you might implement logging ? Leave as exercise.
|
2017-08-08 02:45:19 +03:00
|
|
|
|
|
|
|
7 - BOSS FIGHT - A
|
|
|
|
---
|
|
|
|
Replace the stringly DB layer with something better:
|
|
|
|
- [Selda](https://selda.link/)
|
|
|
|
- [Tisch](https://github.com/k0001/tisch)
|
|
|
|
- [Opaleye](https://hackage.haskell.org/package/opaleye)
|
|
|
|
- [Groundhog](https://github.com/lykahb/groundhog)
|
|
|
|
|
|
|
|
These packages will force a lot of other things to be picked up at the same
|
|
|
|
time, to varying degrees:
|
|
|
|
* Selda : Type level lists, type operators, data structures as tuples initially.
|
|
|
|
* Tisch : Type level HLists, overloaded labels, type families, familiarity with Opaleye.
|
|
|
|
* Opaleye : Arrows, full polymorphic records.
|
|
|
|
* Groundhog : Alien data type definitions using their Template Haskell DSL, is
|
|
|
|
an ORM more than a type safe SQL package (if that makes sense).
|
|
|
|
|
|
|
|
All packages use generics of some description, not sure how much air time they
|
|
|
|
need? Passing mention and throw some links around, move on.
|
|
|
|
|
|
|
|
8 - BOSS FIGHT - B
|
|
|
|
---
|
|
|
|
Integration of 'classy mtl' style application design.
|
|
|
|
|
|
|
|
* Briefly explain the problem with using a transformer stack or newtype'd stack
|
|
|
|
like we have.
|
|
|
|
* Concrete types
|
|
|
|
* Cannot generalise easily to abstract out larger moving parts
|
|
|
|
* Discuss what we want is just constraints, PARAMETRICITY driven development!!
|
|
|
|
* Build intuition for `AsFoo` & `HasFoo`
|
|
|
|
* `mtl` classes are a start, but how do we make this easier?
|
|
|
|
* Describe `CanFoo` and introduce `ConstraintKinds`
|