You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The origami project provides "Monadic folds" to process streams of data in a composable fashion.
Monadic folds come in 2 flavors:
pure folds: for computing things like min, max, average, hash,...
effectul folds: for sinking data to a file for example
The general form of a Fold is
traitFold[M[_], A, B] {
typeSdefstart:M[S]
deffold: (S, A) =>M[S]
defend(s: S):M[B]
}
where:
M must have a Monad instance
A is the type of input elements, being fed one by one to the fold
B is the final result
S is the type of some internal state
start is a method to "initialize" the fold
end is a method to "finalize" the fold
fold is the method called for each element A and current type S
Folds can be composed to produce "larger" folds, doing several things at the same time. For example:
importorg.atnos.origami._importorg.atnos.origami.fold._importorg.atnos.origami.folds._importorg.atnos.origami.syntax.foldable._importcats.Evalimportcats.data.EitherTimportcats.implicits._importjava.io.PrintWritertypeSafe[A] =EitherT[Eval, Throwable, A]
defprotect[A](a: =>A):Safe[A] =EitherT.right(Eval.later(a))
defsaveToFile(path: String):Sink[Safe, Int] =
bracket(
// create a new writer
protect(newPrintWriter(path)))(
// write a new line in the file
(w, i: Int) => protect { w.write(s"i=$i\n"); w })(
// close the writer
w => protect(w.close))
valstats:Fold[Safe, Int, ((Int, Int), Double)] =
(minimumOr(0) <*> maximumOr(Int.MaxValue) <*> averageDouble).into[Safe] <*
saveToFile("target/readme-example")
valelements= (1 to 10).toList
elements.foldWith(stats).value.value
In the example above we create a stats fold composed from:
3 pure folds assembled with <*> (the zip operator)
1 effectful fold saveToFile using the Safe monad
The Safe monad is necessary here to use the bracket combinator which creates a Fold acquiring resources at the
beginning of the run and eventually release them. It needs both the ability to deal with errors (with EitherT) and to
delay computations (with Eval).