pub trait Sequence<F, A, TF> {
// Provided method
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> { ... }
}
Expand description
Sequence extends Traversable
with a function that inverts collection
of Applicatives into an Applicative of a collection.
e.g. Vec<Result<T, E>>
to Result<Vec<T>, E>
use std::fs::{DirEntry, File, FileType, ReadDir};
use std::io;
use std::path::{Path, PathBuf};
use naan::prelude::*;
fn is_dir(ent: &DirEntry) -> bool {
ent.file_type()
.fmap(|ft: FileType| ft.is_dir())
.unwrap_or(false)
}
fn is_file(ent: &DirEntry) -> bool {
ent.file_type()
.fmap(|ft: FileType| ft.is_file())
.unwrap_or(false)
}
/// Recursively search directories and their children
/// for all files that match a predicate
fn find_all_rec<P: AsRef<Path>, F: Fn(PathBuf) -> io::Result<bool>>(
path: P,
f: F)
-> io::Result<Vec<PathBuf>> {
let find_matches = |matches: Vec<io::Result<Vec<PathBuf>>>, ent: DirEntry| {
let path_if_found = |found| {
if found {
vec![ent.path()]
} else {
vec![]
}
};
if is_file(&ent) {
matches.append_one(f(ent.path()).fmap(path_if_found))
} else if is_dir(&ent) {
matches.append_one(find_all_rec(ent.path(), &f))
} else {
matches
}
};
std::fs::read_dir(path).bind1(|dir: ReadDir| {
dir.into_iter().collect::<io::Result<Vec<DirEntry>>>()
})
.bind1(|ents: Vec<DirEntry>| {
ents.foldl(find_matches, vec![])
.sequence::<hkt::ResultOk<_>>()
})
.fmap(|vv: Vec<Vec<_>>| vv.concat())
}
/// ...or using try syntax:
fn find_all_rec2<P: AsRef<Path>, F: Fn(PathBuf) -> io::Result<bool>>(
path: P,
f: F)
-> io::Result<Vec<PathBuf>> {
let find_matches = |matches: Vec<io::Result<Vec<PathBuf>>>, ent: DirEntry| {
let path_if_found = |found| {
if found {
vec![ent.path()]
} else {
vec![]
}
};
if is_file(&ent) {
matches.append_one(f(ent.path()).fmap(path_if_found))
} else if is_dir(&ent) {
matches.append_one(find_all_rec(ent.path(), &f))
} else {
matches
}
};
let dir = std::fs::read_dir(path)?;
let ents = dir.into_iter().collect::<io::Result<Vec<DirEntry>>>()?;
let out: Vec<Vec<PathBuf>> = ents.foldl(find_matches, Vec::<io::Result<Vec<PathBuf>>>::new())
.sequence::<hkt::ResultOk<_>>()?;
Ok(out.concat())
}
Provided Methods§
sourcefn 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>,
See Sequence