1
1
mirror of https://github.com/qfpl/applied-fp-course.git synced 2024-11-27 01:23:00 +03:00
applied-fp-course/README.md

192 lines
7.0 KiB
Markdown
Raw Normal View History

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
- Encoding / Decoding messages (JSON & Binary)
- 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
Tonys simpler version:
---
NB : No doctests yet :(
- 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
* Level 04 : Testing & Tools (hspec & ghcid)
2017-08-10 09:25:08 +03:00
* Level 05 : Database layer (postgresql-simple)
* Level 06 : ReaderT & Refactoring
-- Working on this one...
2017-08-10 09:25:08 +03:00
* Level 07 : ExceptT & Refactoring
-- NEXT...
2017-08-10 09:25:08 +03:00
* Level 08 : (Bonus Round) Lenses & Refactoring
-- 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
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 ?
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.
Subgoals (?)
========
- ghcid
- hedgehog
- cabal files
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.
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?).
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.
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.
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 10:14:29 +03:00
** Prompt discussion about what lurks beneath the surface of the `IO a` query functionality.
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.
* 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`