Compare commits
10 Commits
38d9cd6072
...
7ee4cb51b2
Author | SHA1 | Date |
---|---|---|
Sanchayan Maity | 7ee4cb51b2 | |
Sanchayan Maity | 277dc29645 | |
Sanchayan Maity | 27ef8809b8 | |
Sanchayan Maity | d69d5eea05 | |
Sanchayan Maity | e039f32bc5 | |
Sanchayan Maity | a70e8d66ba | |
Sanchayan Maity | 3053851eb1 | |
Sanchayan Maity | 09bfc5582b | |
Sanchayan Maity | e4c13abefa | |
Sanchayan Maity | 08d89b1663 |
|
@ -1,3 +1,3 @@
|
|||
free-monad-example.cabal
|
||||
.stack-work/
|
||||
dist-newstyle
|
||||
*~
|
||||
|
|
45
README.md
45
README.md
|
@ -1 +1,44 @@
|
|||
# free-monad-example
|
||||
# Free Monad sample project
|
||||
|
||||
Using [Hydra](https://github.com/graninas/Hydra) as a reference for study.
|
||||
|
||||
# Library
|
||||
|
||||
https://hackage.haskell.org/package/free
|
||||
|
||||
# Resources
|
||||
|
||||
- [What are free monads](https://stackoverflow.com/questions/13352205/what-are-free-monads)
|
||||
- [You could have invented free monads](http://www.haskellforall.com/2012/06/you-could-have-invented-free-monads.html)
|
||||
- [Purify code using free monads](http://www.haskellforall.com/2012/07/purify-code-using-free-monads.html)
|
||||
- [What does free buy us](https://www.parsonsmatt.org/2017/09/22/what_does_free_buy_us.html)
|
||||
- [Random gist](https://gist.github.com/CMCDragonkai/165d9a598b8fb333ea65)
|
||||
- [Free Monads](https://www.tweag.io/blog/2018-02-05-free-monads/)
|
||||
- [Many roads to free monads](https://www.schoolofhaskell.com/user/dolio/many-roads-to-free-monads)
|
||||
- [Hierarchical Free Monads & Software Design in Functional Programming by Alexander Granin](https://www.youtube.com/watch?v=3GKQ4ni2pS0)
|
||||
|
||||
# Free Monads Performance
|
||||
|
||||
- [Asymptotic Improvement of Computations over Free Monads](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.143.2323&rep=rep1&type=pdf)
|
||||
- [Free Monads for less - Part 1](http://comonad.com/reader/2011/free-monads-for-less/)
|
||||
- [Free Monads for less - Part 2](http://comonad.com/reader/2011/free-monads-for-less-2/)
|
||||
- [Free Monads for less - Part 3](http://comonad.com/reader/2011/free-monads-for-less-3/)
|
||||
- [Kan Extensions](http://comonad.com/reader/2008/kan-extensions/)
|
||||
- [The Free and The Furious: And by 'Furious' I mean Codensity](https://www.youtube.com/watch?v=EiIZlX_k89Y)
|
||||
- [Effects for less - Great talk, must watch](https://www.youtube.com/watch?v=0jI-AlWEwYI)
|
||||
- [Problem Set - The Codensity transformation](http://blog.ezyang.com/2012/01/problem-set-the-codensity-transformation/)
|
||||
|
||||
# Fix Point
|
||||
|
||||
- [Fix and Recursion](https://en.wikibooks.org/wiki/Haskell/Fix_and_recursion)
|
||||
- [The Y Combinator](https://mvanier.livejournal.com/2700.html)
|
||||
- [The Y Combinator - Slight Return](https://mvanier.livejournal.com/2897.html)
|
||||
- [A series of articles on Recursion schemes](https://blog.sumtypeofway.com/archive.html)
|
||||
- [Understanding Algebras](https://www.schoolofhaskell.com/user/bartosz/understanding-algebras)
|
||||
|
||||
# Jupyter Notebooks (Includes the one used for Free Monad)
|
||||
- [https://gitlab.com/SanchayanMaity/haskell-notebooks](https://gitlab.com/SanchayanMaity/haskell-notebooks)
|
||||
|
||||
# youtube Recording of the talk
|
||||
|
||||
https://www.youtube.com/watch?v=fhu1UQel5eo
|
||||
|
|
17
app/Main.hs
17
app/Main.hs
|
@ -1,6 +1,21 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Main where
|
||||
|
||||
import Database.PostgreSQL.Simple
|
||||
import Data.Text (pack)
|
||||
import Lib
|
||||
|
||||
dslOperations :: Connection -> DSL ()
|
||||
dslOperations conn = do
|
||||
logMsg "Logging from inside the DSL"
|
||||
xs <- runQuery conn "select 2 + 2"
|
||||
logMsg $ pack $ show (xs :: [Only Int])
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn "Free monad example"
|
||||
main = do
|
||||
putStrLn "Free monad example"
|
||||
conn <- connect defaultConnectInfo {
|
||||
connectDatabase = "postgres"
|
||||
}
|
||||
runDSL $ dslOperations conn
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
cabal-version: 1.12
|
||||
name: free-monad-example
|
||||
version: 0.1.0.0
|
||||
description:
|
||||
Please see the README on GitHub at <https://github.com/sanchayanmaity/free-monad-example#readme>
|
||||
|
||||
homepage: https://github.com/sanchayanmaity/free-monad-example#readme
|
||||
bug-reports: https://github.com/sanchayanmaity/free-monad-example/issues
|
||||
author: Sanchayan Maity
|
||||
maintainer: maitysanchayan@gmail.com
|
||||
copyright: 2020 Sanchayan Maity
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
build-type: Simple
|
||||
extra-source-files: README.md
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/sanchayanmaity/free-monad-example
|
||||
|
||||
library
|
||||
exposed-modules:
|
||||
DB.Interpreter
|
||||
DB.Language
|
||||
Lib
|
||||
Logger.Interpreter
|
||||
Logger.Language
|
||||
|
||||
other-modules: Paths_free_monad_example
|
||||
hs-source-dirs: src
|
||||
ghc-options: -Wall -Wunused-binds
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
, free
|
||||
, postgresql-simple
|
||||
, text
|
||||
|
||||
default-language: Haskell2010
|
||||
|
||||
executable free-monad-example-exe
|
||||
main-is: Main.hs
|
||||
other-modules: Paths_free_monad_example
|
||||
hs-source-dirs: app
|
||||
ghc-options: -Wall -Wunused-binds -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
, free
|
||||
, free-monad-example
|
||||
, postgresql-simple
|
||||
, text
|
||||
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite free-monad-example-test
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: Spec.hs
|
||||
other-modules: Paths_free_monad_example
|
||||
hs-source-dirs: test
|
||||
ghc-options: -Wall -Wunused-binds -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends:
|
||||
base >=4.7 && <5
|
||||
, free
|
||||
, free-monad-example
|
||||
, postgresql-simple
|
||||
, text
|
||||
|
||||
default-language: Haskell2010
|
13
hie.yaml
13
hie.yaml
|
@ -1,13 +0,0 @@
|
|||
cradle:
|
||||
stack:
|
||||
- path: "./src"
|
||||
component: "free-monad-example:lib"
|
||||
|
||||
- path: "./app/Main.hs"
|
||||
component: "free-monad-example:exe:free-monad-example-exe"
|
||||
|
||||
- path: "./app/Paths_free_monad_example.hs"
|
||||
component: "free-monad-example:exe:free-monad-example-exe"
|
||||
|
||||
- path: "./test"
|
||||
component: "free-monad-example:test:free-monad-example-test"
|
|
@ -22,8 +22,6 @@ dependencies:
|
|||
- base >= 4.7 && < 5
|
||||
- free
|
||||
- postgresql-simple
|
||||
- servant
|
||||
- servant-server
|
||||
- text
|
||||
|
||||
ghc-options:
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
module DB.Interpreter where
|
||||
|
||||
import Control.Exception (throwIO)
|
||||
import Control.Monad.Free.Church (foldF)
|
||||
import Database.PostgreSQL.Simple (Connection, Query)
|
||||
import DB.Language
|
||||
|
||||
interpretSqlDBMethod :: Connection -> Query -> SqlDBMethodF a -> IO a
|
||||
interpretSqlDBMethod conn squery (SqlDBMethod runner next) = next <$> runner conn squery
|
||||
interpretSqlDBMethod _ _ (SqlThrowException exception _) = throwIO exception
|
||||
|
||||
runDB :: Connection -> Query -> SqlDb a -> IO a
|
||||
runDB conn squery = foldF $ interpretSqlDBMethod conn squery
|
|
@ -0,0 +1,23 @@
|
|||
{-# LANGUAGE GADTs #-}
|
||||
|
||||
module DB.Language where
|
||||
|
||||
import Control.Exception (Exception)
|
||||
import Control.Monad.Free.Church (F, liftF)
|
||||
import Database.PostgreSQL.Simple (Connection, FromRow, Query)
|
||||
|
||||
data SqlDBMethodF next where
|
||||
SqlDBMethod :: FromRow r => (Connection -> Query -> IO [r]) -> ([r] -> next) -> SqlDBMethodF next
|
||||
SqlThrowException :: Exception e => e -> (a -> next) -> SqlDBMethodF next
|
||||
|
||||
instance Functor SqlDBMethodF where
|
||||
fmap f (SqlDBMethod runner next) = SqlDBMethod runner (f . next)
|
||||
fmap f (SqlThrowException exceptionMsg next) = SqlThrowException exceptionMsg (f . next)
|
||||
|
||||
type SqlDb = F SqlDBMethodF
|
||||
|
||||
sqlDbMethod :: FromRow r => (Connection -> Query -> IO [r]) -> SqlDb [r]
|
||||
sqlDbMethod action = liftF $ SqlDBMethod action id
|
||||
|
||||
sqlThrowException :: Exception e => e -> SqlDb a
|
||||
sqlThrowException exception = liftF $ SqlThrowException exception id
|
58
src/Lib.hs
58
src/Lib.hs
|
@ -1,55 +1,15 @@
|
|||
{-# LANGUAGE GADTs #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE Rank2Types #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
|
||||
module Lib where
|
||||
|
||||
import Control.Exception
|
||||
import Control.Monad.Free.Church
|
||||
import Database.PostgreSQL.Simple
|
||||
import Data.Text
|
||||
|
||||
data SqlDBMethodF next where
|
||||
SqlDBMethod :: FromRow r => (Connection -> Query -> IO [r]) -> ([r] -> next) -> SqlDBMethodF next
|
||||
SqlThrowException :: Exception e => e -> (a -> next) -> SqlDBMethodF next
|
||||
|
||||
instance Functor SqlDBMethodF where
|
||||
fmap f (SqlDBMethod runner next) = SqlDBMethod runner (f . next)
|
||||
fmap f (SqlThrowException exceptionMsg next) = SqlThrowException exceptionMsg (f . next)
|
||||
|
||||
type SqlDb = F SqlDBMethodF
|
||||
|
||||
sqlDbMethod :: FromRow r => (Connection -> Query -> IO [r]) -> SqlDb [r]
|
||||
sqlDbMethod action = liftF $ SqlDBMethod action id
|
||||
|
||||
sqlThrowException :: Exception e => e -> SqlDb a
|
||||
sqlThrowException exception = liftF $ SqlThrowException exception id
|
||||
|
||||
interpretSqlDBMethod :: Connection -> Query -> SqlDBMethodF a -> IO a
|
||||
interpretSqlDBMethod conn squery (SqlDBMethod runner next) = next <$> runner conn squery
|
||||
interpretSqlDBMethod _ _ (SqlThrowException exception _) = throwIO exception
|
||||
|
||||
runDB :: Connection -> Query -> SqlDb a -> IO a
|
||||
runDB conn squery = foldF $ interpretSqlDBMethod conn squery
|
||||
|
||||
data LoggerMethodF next where
|
||||
LogMessage :: Text -> (() -> next) -> LoggerMethodF next
|
||||
|
||||
instance Functor LoggerMethodF where
|
||||
fmap f (LogMessage msg next) = LogMessage msg (f . next)
|
||||
|
||||
type Logger = F LoggerMethodF
|
||||
|
||||
logMessage :: Text -> Logger ()
|
||||
logMessage msg = liftF $ LogMessage msg id
|
||||
|
||||
interpretLoggerMethod :: LoggerMethodF a -> IO a
|
||||
interpretLoggerMethod (LogMessage msg next) = next <$> print msg
|
||||
|
||||
runLogger :: Logger () -> IO ()
|
||||
runLogger = foldF interpretLoggerMethod
|
||||
import Control.Monad.Free.Church (F, foldF, liftF, MonadFree)
|
||||
import Database.PostgreSQL.Simple (Connection, FromRow, Query, query_)
|
||||
import Data.Text (Text)
|
||||
import DB.Interpreter (runDB)
|
||||
import DB.Language (SqlDb, sqlDbMethod)
|
||||
import Logger.Interpreter (runLogger)
|
||||
import Logger.Language (Logger, logMessage)
|
||||
|
||||
data DSLMethod next where
|
||||
LogMsg :: Logger () -> (() -> next) -> DSLMethod next
|
||||
|
@ -63,9 +23,9 @@ type DSL = F DSLMethod
|
|||
|
||||
interpretDSLMethod :: DSLMethod a -> IO a
|
||||
interpretDSLMethod (LogMsg logger next) =
|
||||
fmap next $ runLogger logger
|
||||
next <$> runLogger logger
|
||||
interpretDSLMethod (RunQuery conn squery sql next) =
|
||||
fmap next $ runDB conn squery sql
|
||||
next <$> runDB conn squery sql
|
||||
|
||||
runDSL :: DSL () -> IO ()
|
||||
runDSL = foldF interpretDSLMethod
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
module Logger.Interpreter where
|
||||
|
||||
import Control.Monad.Free.Church (foldF)
|
||||
import Logger.Language
|
||||
|
||||
interpretLoggerMethod :: LoggerMethodF a -> IO a
|
||||
interpretLoggerMethod (LogMessage msg next) = next <$> print msg
|
||||
|
||||
runLogger :: Logger () -> IO ()
|
||||
runLogger = foldF interpretLoggerMethod
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{-# LANGUAGE GADTs #-}
|
||||
|
||||
module Logger.Language where
|
||||
|
||||
import Control.Monad.Free.Church (F, liftF)
|
||||
import Data.Text (Text)
|
||||
|
||||
data LoggerMethodF next where
|
||||
LogMessage :: Text -> (() -> next) -> LoggerMethodF next
|
||||
|
||||
instance Functor LoggerMethodF where
|
||||
fmap f (LogMessage msg next) = LogMessage msg (f . next)
|
||||
|
||||
type Logger = F LoggerMethodF
|
||||
|
||||
logMessage :: Text -> Logger ()
|
||||
logMessage msg = liftF $ LogMessage msg id
|
||||
|
66
stack.yaml
66
stack.yaml
|
@ -1,66 +0,0 @@
|
|||
# This file was automatically generated by 'stack init'
|
||||
#
|
||||
# Some commonly used options have been documented as comments in this file.
|
||||
# For advanced use and comprehensive documentation of the format, please see:
|
||||
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||
|
||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||
# A snapshot resolver dictates the compiler version and the set of packages
|
||||
# to be used for project dependencies. For example:
|
||||
#
|
||||
# resolver: lts-3.5
|
||||
# resolver: nightly-2015-09-21
|
||||
# resolver: ghc-7.10.2
|
||||
#
|
||||
# The location of a snapshot can be provided as a file or url. Stack assumes
|
||||
# a snapshot provided as a file might change, whereas a url resource does not.
|
||||
#
|
||||
# resolver: ./custom-snapshot.yaml
|
||||
# resolver: https://example.com/snapshots/2018-01-01.yaml
|
||||
resolver: lts-15.15
|
||||
|
||||
# User packages to be built.
|
||||
# Various formats can be used as shown in the example below.
|
||||
#
|
||||
# packages:
|
||||
# - some-directory
|
||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||
# subdirs:
|
||||
# - auto-update
|
||||
# - wai
|
||||
packages:
|
||||
- .
|
||||
# Dependency packages to be pulled from upstream that are not in the resolver.
|
||||
# These entries can reference officially published versions as well as
|
||||
# forks / in-progress versions pinned to a git hash. For example:
|
||||
#
|
||||
# extra-deps:
|
||||
# - acme-missiles-0.3
|
||||
# - git: https://github.com/commercialhaskell/stack.git
|
||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||
#
|
||||
# extra-deps: []
|
||||
|
||||
# Override default flag values for local packages and extra-deps
|
||||
# flags: {}
|
||||
|
||||
# Extra package databases containing global packages
|
||||
# extra-package-dbs: []
|
||||
|
||||
# Control whether we use the GHC we find on the path
|
||||
# system-ghc: true
|
||||
#
|
||||
# Require a specific version of stack, using version ranges
|
||||
# require-stack-version: -any # Default
|
||||
# require-stack-version: ">=2.3"
|
||||
#
|
||||
# Override the architecture used by stack, especially useful on Windows
|
||||
# arch: i386
|
||||
# arch: x86_64
|
||||
#
|
||||
# Extra directories used by stack for building
|
||||
# extra-include-dirs: [/path/to/dir]
|
||||
# extra-lib-dirs: [/path/to/dir]
|
||||
#
|
||||
# Allow a newer minor version of GHC than the snapshot specifies
|
||||
# compiler-check: newer-minor
|
|
@ -1,12 +0,0 @@
|
|||
# This file was autogenerated by Stack.
|
||||
# You should not edit this file by hand.
|
||||
# For more information, please see the documentation at:
|
||||
# https://docs.haskellstack.org/en/stable/lock_files
|
||||
|
||||
packages: []
|
||||
snapshots:
|
||||
- completed:
|
||||
size: 496112
|
||||
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/15/15.yaml
|
||||
sha256: 86169722ad0056ffc9eacc157ef80ee21d7024f92c0d2961c89ccf432db230a3
|
||||
original: lts-15.15
|
Loading…
Reference in New Issue