pub struct IO<T>(_);
Expand description
Lazy managed I/O
This structure represents the concept of any & all side-effecting computations, wrapping lazy IO in a monad.
Value Proposition
Managed IO allows you to wrap procedural code in an ergonomic declarative interface.
For some problems, it can be valuable to express a series of computations and side-effects as a “pipe” that data will eventually flow through, rather than a sequence of imperative statements.
Use of IO doesn’t come with any inherent performance gains or costs (due to IO not relying on heap allocations or dynamic dispatch) and is a mostly stylistic choice.
Initializing an IO
Values already in scope that need to be wrapped in IO
can be lifted with IO::pure
.
Using IO
to defer computations until some later time can be done with IO::suspend
.
Executing an IO
IO<A>
(and the types returned by map_
/bind_
/apply_
) implement the
IOLike
trait, which provides a function fn exec(self) -> A
IO
in parameter and return positions
Use impl IOLike<A>
instead of concrete types like IO<A>
or Suspend<A>
.
use core::ops::Add;
use naan::io;
use naan::prelude::*;
fn add12(n: usize) -> usize {
n + 12
}
// Prefer:
fn foo(io: impl IOLike<usize>) -> impl IOLike<usize> {
io.map_(add12)
}
// Over:
fn bar(io: IO<usize>) -> io::Map<fn(usize) -> usize, usize, usize, IO<usize>> {
io.map_(add12)
}
Most of the types you’ll interact with are “surrogate” types that are still conceptually “an IO,” but represent different transformations:
Suspend
(fromIO::suspend
)Map
(fromFunctorSurrogate::map_
)Bind
(fromMonadSurrogate::bind_
)Apply
(fromApplySurrogate::apply_
)
IO
has been designed with no heap allocations or dynamic dispatch,
and accomplishes this by progressively building a stack of structs that
store data & work to do.
This stack is collapsed when you call [IOLike.exec
].
Note, that IOLike
provides map_
, apply_
, and bind_
,
so for most usecases you don’t need to think or worry about concrete types.
use core::ops::Add;
use std::cell::Cell;
use naan::prelude::*;
fn get_number_from_network() -> impl IOLike<usize> {
IO::suspend(|()| 1111)
}
let x = Cell::new(0usize);
let lazy = IO::suspend(|()| "123").map_(|s| usize::from_str_radix(s, 10).unwrap())
.map_(|n| {
x.set(x.get() + 1);
n
})
.map_((|a, b| a + b).curry()) // 123 + _
.apply_(get_number_from_network()); // 123 + 1111
assert_eq!(x.get(), 0);
assert_eq!(lazy.exec(), 1234);
assert_eq!(x.get(), 1);
Implementations§
Trait Implementations§
Auto Trait Implementations§
impl<T> RefUnwindSafe for IO<T>where T: RefUnwindSafe,
impl<T> Send for IO<T>where T: Send,
impl<T> Sync for IO<T>where T: Sync,
impl<T> Unpin for IO<T>where T: Unpin,
impl<T> UnwindSafe for IO<T>where T: UnwindSafe,
Blanket Implementations§
source§impl<I, AB, TofA> ApplySurrogate<IO, AB, TofA> for Iwhere
I: Equiv<To = IO<AB>> + IOLike<AB>,
impl<I, AB, TofA> ApplySurrogate<IO, AB, TofA> for Iwhere I: Equiv<To = IO<AB>> + IOLike<AB>,
§type ApplyOutput = Apply<A, B, AB, TofA, I>
type ApplyOutput = Apply<A, B, AB, TofA, I>
source§impl<I, A> MonadSurrogate<IO, A> for Iwhere
I: Equiv<To = IO<A>> + IOLike<A>,
impl<I, A> MonadSurrogate<IO, A> for Iwhere I: Equiv<To = IO<A>> + IOLike<A>,
§type BindOutput = Bind<AMB, A, B, I>
type BindOutput = Bind<AMB, A, B, I>
source§fn bind_<B, AMB>(
self,
f: AMB
) -> <I as MonadSurrogate<IO, A>>::BindOutput<B, AMB>where
AMB: F1<A, Ret = <IO as HKT1>::T<B>>,
fn bind_<B, AMB>( self, f: AMB ) -> <I as MonadSurrogate<IO, A>>::BindOutput<B, AMB>where AMB: F1<A, Ret = <IO as HKT1>::T<B>>,
A -> M<B>
to transform something
akin to M<A>
to something akin to M<B>
.source§impl<F, A, TF, T> Sequence<F, A, TF> for T
impl<F, A, TF, T> Sequence<F, A, TF> for T
source§fn sequence<Ap>(self) -> Ap::T<F::T<A>>where
Self: Sized + Traversable<F, Ap::T<A>, A, TF> + Foldable<F, Ap::T<A>>,
Ap: HKT1,
Ap::T<A>: Applicative<Ap, A> + ApplyOnce<Ap, A>,
Ap::T<TF>: Applicative<Ap, TF> + ApplyOnce<Ap, TF>,
Ap::T<F::T<A>>: Applicative<Ap, F::T<A>> + ApplyOnce<Ap, F::T<A>>,
F: HKT1<T<Ap::T<A>> = Self>,
fn sequence<Ap>(self) -> Ap::T<F::T<A>>where Self: Sized + Traversable<F, Ap::T<A>, A, TF> + Foldable<F, Ap::T<A>>, Ap: HKT1, Ap::T<A>: Applicative<Ap, A> + ApplyOnce<Ap, A>, Ap::T<TF>: Applicative<Ap, TF> + ApplyOnce<Ap, TF>, Ap::T<F::T<A>>: Applicative<Ap, F::T<A>> + ApplyOnce<Ap, F::T<A>>, F: HKT1<T<Ap::T<A>> = Self>,
Sequence