Hydra Framework
All-in-one framework for writing Haskell apps which use the following features out of the box:
- Multithreading
- Safe STM-powered concurrency
- KV DB functionality (Redis & RocksDB backends supported)
- SQL DB functionality (beam incorporated, SQLite supported, PG & MySQL possible)
- CLI apps support
- Logging
- Random data generation
- Many others
With the framework, you can create complex applications which have a good maintainability, testability, simplicity, have a good structure and are easy to read and change. The key principles of the framework:
- Layered architecture
- Separation of concerns (interfaces, business logic, runtime and implementation)
- Simple and convenient eDSLs
- Testable and maintainable code
The Hydra Project
This project demonstrates the principles of Software Design and Architecture in pure Functional Programming. Hydra has several separate frameworks based on different engines for easy comparison:
- Final Tagless engine
- Free monad based engine
- Church-encoded Free monad based engine
The core idea of the two Free monadic frameworks is known as Hierarchical Free Monads.
The project is a showcase for my book Functional Design and Architecture. The approaches presented in Hydra are well-described and rationalized in the book, so you may obtain even more info about best practices and ideas of how to write a good Haskell code.
Note The Free monad based framework is the most developed by functionality. I'm working on synchronizing the functionality between all the engines.
Building dependencies
Ubuntu:
$ sudo apt-get install libpq-dev librocksdb-dev
MacOS:
brew install rocksdb postgresql
Building and running
Use stack for building all the framework and apps:
$ stack build
You can also switch the optimizations off and use several threads for building:
$ stack build --fast -j4
Running a project is also simple:
$ stack exec labyrinth
To load a subproject into GHCi, use the following command:
$ stack ghci labyrinth:exe:labyrinth
Sample applications
There are several sample applications:
- Astro app: web server (with servant) and CLI client tool which allows to track meteors (tool for astronomers).
- PerfTestApp: an application you can run to measure the performance of the three engines.
- PerfTestApp2: another application you can run to measure the performance of the three engines.
- MeteorCounter: application which demonstrates the usage of STM and multithreading using three engines.
- Labyrinth: a game about exploring the labyrinth with a CLI interactive interface.
Code samples
Sample SQL-related code
createMeteor :: MeteorTemplate -> D.SqlConn BS.SqliteM -> L.AppL MeteorId
createMeteor mtp@(MeteorTemplate {..}) conn = do
L.logInfo $ "Inserting meteor into SQL DB: " <> show mtp
let time = Time.UTCTime (toEnum 1) (Time.secondsToDiffTime 0)
doOrFail
$ L.scenario
$ L.runDB conn
$ L.insertRows
$ B.insert (SqlDB._meteors SqlDB.astroDb)
$ B.insertExpressions
[ SqlDB.Meteor B.default_
(B.val_ size)
(B.val_ mass)
(B.val_ azimuth)
(B.val_ altitude)
(B.val_ time)
]
let predicate meteorDB
= (SqlDB._meteorSize meteorDB ==. B.val_ size)
&&. (SqlDB._meteorMass meteorDB ==. B.val_ mass)
&&. (SqlDB._meteorAzimuth meteorDB ==. B.val_ azimuth)
&&. (SqlDB._meteorAltitude meteorDB ==. B.val_ altitude)
m <- doOrFail
$ L.scenario
$ L.runDB conn
$ L.findRow
$ B.select
$ B.limit_ 1
$ B.filter_ predicate
$ B.all_ (SqlDB._meteors SqlDB.astroDb)
pure $ SqlDB._meteorId $ fromJust m
Additional materials
Checkout the following materials to learn more about he Hierarchical Free Monads approach used in Hydra:
- Hierarchical Free Monads: The Most Developed Approach In Haskell (And The Death Of Final Tagless)
- Hierarchical Free Monads and Software Design in Functional Programming (Talk, Eng) | Slides (Eng)
- Final Tagless vs Free Monad (Talk, Rus) | Slides (Eng)
- Automatic Whitebox Testing with Free Monads (Talk, Eng) | Slides (Eng)
- Automatic whitebox testing with Free Moands (Showcase, Article)