Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d32f30d
commit 4ea254f
Showing
1 changed file
with
37 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# 4. Use Handle to model Effects | ||
|
||
Date: 2021-06-08 | ||
|
||
## Status | ||
|
||
Accepted | ||
|
||
## Context | ||
|
||
* Given we are structuring Hydra node as a [reactive core](0002-reactive-core) we need a way to ensure a strict separation of pure and impure (or effectful) code | ||
* Various _patterns_ have been proposed in Haskell to model effects: | ||
* [Tagless final encoding](http://okmij.org/ftp/tagless-final/index.html) also known as _MTL-style_ although using typeclasses to implement is [not necessary](https://www.foxhound.systems/blog/final-tagless/), whereby Effect(s) are expressed as typeclass(es) which are propagated as constraints | ||
* [Free monads](https://reasonablypolymorphic.com/blog/freer-monads/), or any variant thereof like Eff, freer, extensible-effects, whereby effect(s) are expressed as ADTs which are _interpreted_ in the context of an _Effect stack_ | ||
* [Handle](https://jaspervdj.be/posts/2018-03-08-handle-pattern.html) pattern also known as _record-of-functions_ whereby effects are grouped together in a datatype with a single record constructor | ||
* All options considered have both advocates and detractors and there is no widely accepted pattern | ||
* We did a couple experiments to explore various options | ||
|
||
## Decision | ||
|
||
* Effectful components of the Hydra node will be defined using the _Handle pattern_ | ||
|
||
## Consequences | ||
|
||
### Effects | ||
|
||
* For example, the on-chain component is defined as: | ||
``` | ||
newtype OnChain m = OnChain | ||
{ postTx :: MonadThrow m => OnChainTx -> m () | ||
} | ||
``` | ||
* Instantiation to concrete IO is pushed at the outermost layer, eg. in the `Main` or tests | ||
|
||
## Additional comments | ||
|
||
* These tradeoffs also appear in other functional languages like [F#](https://medium.com/@dogwith1eye/prefer-records-of-functions-to-interfaces-d6413af4d2c3) |