Trait naan::traverse::Sequence

source ·
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§

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>,

Implementors§

source§

impl<F, A, TF, T> Sequence<F, A, TF> for T