Skip to content

Latest commit

 

History

History
138 lines (104 loc) · 5.05 KB

README.md

File metadata and controls

138 lines (104 loc) · 5.05 KB

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: