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
WARNING: THIS IS AN ALPHA RELEASE AND SHOULDN'T BE CONSUMED WITH CARE! NOT FOR PRODUCTION.
Bug fixing and TODO resolving release, with some minor featurettes!
For those that don't know yet (and there's no reason to think you should, because I haven't announced it yet) -- the Pipes Effect system now has the ability to lift any monad into its stack (previously it only allowed Aff to be lifted). It is now a general monad transformer like ReaderT, OptionT, EitherT, etc.
As, with all monad-transfomers, when you 'run' the transformer, it generates the lifted monad. You can think of this being like a mini-compiler that takes the monad stack and compiles down to the inner-most monad, which can then just be run as normal.
The problem for Pipes is that there's usually lots of recursion, repetition (using repeat, retry), or iteration (using yieldAll, etc.). This is problematic when you don't know anything about the inner monad. The transformer can't run the inner monad, because it only has access to the Monad interface (Bind) and the inherited interfaces of Applicative and Functor (Apply, Action, Map, and Pure). So, doing iteration requires recursion, and recursion blows the stack in C#.
Previously Pipes were able to directly Run the Aff because the Pipe system knew it was working only with Aff. This allowed it to flatten the recursion.
Anyway, now Pipes has internal support for any Foldable. That means yieldAll(...) can take a sequence from any foldable (Range, EnumerableM, HashMap, HashSet, Lst, Map, Seq, Either, Option, Validation, Identity, ... and any you write) and yield the values within the structure through the pipe. Functions like repeat(ma) - which continually repeat an operation until it fails - have also been implemented internally as something that iterates over an infinite foldable.
This functionality has been enabled by adding a new method to the Applicative trait: Actions. You might know the existing Action(K<M, A> ma, K<M, B> mb) method that runs the first applicative (ma), ignores its result, and then runs the second applicative mb, returning its result.
Actions instead takes an IEnumerable<K<M, A>>:
K<F,A>Actions<A>(IEnumerable<K<F,A>>fas)
It runs each applicative action and ignores its result, returning the result of the last item. That means a sequence of Proxy values (Proxy is the monad-transformer for pipes) can be mapped - the map will just run (using RunEffect) the Proxy - producing a sequence of whatever the lifted inner-monad is for the Proxy. This lazy sequence of monads can then be invoked by calling Actions on it, which will lazily walk the sequence, evaluating the inner-monad one-by-one.
There is a default implementation, but it has the same lack of knowledge that Pipes had, so it should be overridden for computation based applicatives (that usually need invoking with without an argument). Here's the override for Eff<RT, A>:
staticK<Eff<RT>,A>Applicative<Eff<RT>>.Actions<A>(IEnumerable<K<Eff<RT>,A>>fas)=>fromsingetState<A>()fromrinEff<RT,A>.Lift(rt =>{Fin<A>rs= Errors.SequenceEmpty;foreach(var kfa in fas){varfa= kfa.As();rs= fa.Run(rt, s.Resources, s.EnvIO);if(rs.IsFail)returnrs;}returnrs;})selectr;
You can see how:
It's able to gather information, like the runtime, resources, and IO environment.
It knows how to run itself, whereas the generic transformer can't.
It can shortcut the operation when any effect fails.
And so, if you want to use your own monads with Pipes then you should implement Actions.
There's still more to do with Pipes, but all of the examples in EffectsExamples now work, which is a good sign!
WARNING: THIS IS AN ALPHA RELEASE AND SHOULDN'T BE CONSUMED WITH CARE! NOT FOR PRODUCTION.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Bug fixing and TODO resolving release, with some minor featurettes!
For those that don't know yet (and there's no reason to think you should, because I haven't announced it yet) -- the Pipes
Effect
system now has the ability to lift any monad into its stack (previously it only allowedAff
to be lifted). It is now a general monad transformer likeReaderT
,OptionT
,EitherT
, etc.As, with all monad-transfomers, when you 'run' the transformer, it generates the lifted monad. You can think of this being like a mini-compiler that takes the monad stack and compiles down to the inner-most monad, which can then just be run as normal.
The problem for Pipes is that there's usually lots of recursion, repetition (using
repeat
,retry
), or iteration (usingyieldAll
, etc.). This is problematic when you don't know anything about the inner monad. The transformer can't run the inner monad, because it only has access to theMonad
interface (Bind
) and the inherited interfaces ofApplicative
andFunctor
(Apply
,Action
,Map
, andPure
). So, doing iteration requires recursion, and recursion blows the stack in C#.Anyway, now Pipes has internal support for any
Foldable
. That meansyieldAll(...)
can take a sequence from any foldable (Range
,EnumerableM
,HashMap
,HashSet
,Lst
,Map
,Seq
,Either
,Option
,Validation
,Identity
, ... and any you write) and yield the values within the structure through the pipe. Functions likerepeat(ma)
- which continually repeat an operation until it fails - have also been implemented internally as something that iterates over an infinite foldable.This functionality has been enabled by adding a new method to the
Applicative
trait:Actions
. You might know the existingAction(K<M, A> ma, K<M, B> mb)
method that runs the first applicative (ma
), ignores its result, and then runs the second applicativemb
, returning its result.Actions
instead takes anIEnumerable<K<M, A>>
:It runs each applicative action and ignores its result, returning the result of the last item. That means a sequence of
Proxy
values (Proxy
is the monad-transformer for pipes) can be mapped - the map will just run (usingRunEffect
) the Proxy - producing a sequence of whatever the lifted inner-monad is for theProxy
. This lazy sequence of monads can then be invoked by callingActions
on it, which will lazily walk the sequence, evaluating the inner-monad one-by-one.There is a default implementation, but it has the same lack of knowledge that Pipes had, so it should be overridden for computation based applicatives (that usually need invoking with without an argument). Here's the override for
Eff<RT, A>
:You can see how:
And so, if you want to use your own monads with Pipes then you should implement
Actions
.There's still more to do with Pipes, but all of the examples in
EffectsExamples
now work, which is a good sign!This discussion was created from the release Language-Ext 5.0 alpha-3.
Beta Was this translation helpful? Give feedback.
All reactions