Trait naan::fun::F1Once

source ·
pub trait F1Once<A> {
    type Ret;

    // Required method
    fn call1(self, a: A) -> Self::Ret;

    // Provided methods
    fn chain<G, C>(self, g: G) -> Compose<Self, G, Self::Ret>
       where Self: Sized,
             G: F1Once<Self::Ret, Ret = C> { ... }
    fn chain_ref<G, BDeref: ?Sized, C>(
        self,
        g: G
    ) -> Compose<Self, Applied1<call_deref<G, Self::Ret, C>, G, Self::Ret, C>, Self::Ret>
       where Self: Sized,
             G: for<'any> F1Once<&'any BDeref, Ret = C>,
             Self::Ret: Deref<Target = BDeref> { ... }
}
Expand description

A function that accepts 1 argument and can be called at most once.

Required Associated Types§

source

type Ret

The type returned by this function

Required Methods§

source

fn call1(self, a: A) -> Self::Ret

Call the function

Provided Methods§

source

fn chain<G, C>(self, g: G) -> Compose<Self, G, Self::Ret>where Self: Sized, G: F1Once<Self::Ret, Ret = C>,

Create a new function that passes this one’s output to g’s input

(Left-to-right function composition)

use std::path::{Path, PathBuf};

use naan::prelude::*;

fn ensure_trailing_slash(s: &str) -> String {
  if !s.ends_with("/") {
    format!("{s}/")
  } else {
    s.into()
  }
}

fn main() {
  let dir_contains_readme = ensure_trailing_slash.chain(|path| format!("{path}README.md"))
                                                 .chain(PathBuf::from)
                                                 .chain_ref(Path::exists);

  assert!(dir_contains_readme.call("toad-lib/toad/toad"));
  assert!(!dir_contains_readme.call("toad-lib/toad"));
}
A Note on Type Errors

TLDR: try chain_ref if the function is a receiver of &self or a similar shape, and if that fails wrap the composed function with Box::new(...) as Box<dyn F1<.., ..>> for more valuable compiler errors.

The type errors from chained composition type errors tend to be very complex.

While debugging type errors like this, it may help to use Box<dyn F1> to provide more type information to the compiler, e.g.

use std::path::{Path, PathBuf};

use naan::prelude::*;

fn ensure_trailing_slash(s: &str) -> String {
  if !s.ends_with("/") {
    format!("{s}/")
  } else {
    s.into()
  }
}

fn main() {
  let dir_contains_readme =
    ensure_trailing_slash.chain(|path| format!("{path}README.md")).chain(PathBuf::from)
                                                                      .chain(Path::exists);

  assert!(dir_contains_readme.call("toad-lib/toad/toad"));
}

produces type error:

error[E0599]: the method `call1` exists for struct `Compose<Compose<Compose<..>, ..>, .., ..>`, but its trait bounds were not satisfied
  --> src/fun/mod.rs:37:31
     |
  19 |   assert!(dir_contains_readme.call1("toad-lib/toad/toad"));
     |                               ^^^^^ method cannot be called on `Compose<Compose<Compose<..>, ..>, .., ..>` due to unsatisfied trait bounds

when we box it, the compiler much more helpfully tells us that the issue is that Path::exists is &Path -> bool, rather than PathBuf -> bool:

fn main() {
  let dir_contains_readme =
    ensure_trailing_slash.chain(|path| format!("{path}README.md")).chain(PathBuf::from)
                                                                  .chain(Path::exists);

  let dir_contains_readme_boxed: Box<dyn F1<&str, Ret = bool>> = Box::new(dir_contains_readme) as _;

  assert!(dir_contains_readme_boxed.call("toad-lib/toad/toad"));
}

yields

error[E0631]: type mismatch in function arguments
  --> src/fun/compose.rs:91:75
   |
17 | ...                   .chain(Path::exists);
   |                        ----- ^^^^^^^^^^^^
   |                        |     |
   |                        |     expected due to this
   |                        |     found signature defined here
   |                        required by a bound introduced by this call
   |
   = note: expected function signature `fn(PathBuf) -> _`
              found function signature `for<'r> fn(&'r Path) -> _`
   = note: required for `for<'r> fn(&'r Path) -> bool {Path::exists}` to implement `F1Once<PathBuf, _>`

Once all type errors are resolved, the Box debugging can be undone and you can use the concrete nested Compose types.

source

fn chain_ref<G, BDeref: ?Sized, C>( self, g: G ) -> Compose<Self, Applied1<call_deref<G, Self::Ret, C>, G, Self::Ret, C>, Self::Ret>where Self: Sized, G: for<'any> F1Once<&'any BDeref, Ret = C>, Self::Ret: Deref<Target = BDeref>,

chain that passes a reference to this function’s return type to function g.

Also performs Deref::deref, allowing you to do things like pipe a Vec to a function expecting a slice or String to a function expecting &str.

Implementors§

source§

impl<F, A, B> F1Once<A> for Fwhere F: FnOnce(A) -> B,

§

type Ret = B

source§

impl<F, A, B, C> F1Once<A> for naan::fun::curry2::Applied0<F, A, B, C>where F: FnOnce(A, B) -> C,

§

type Ret = Curry2<F, Just<A>, Nothing<B>, C>

source§

impl<F, A, B, C> F1Once<B> for naan::fun::curry2::Applied1<F, A, B, C>where F: FnOnce(A, B) -> C,

§

type Ret = C

source§

impl<F, A, B, C, D> F1Once<A> for naan::fun::curry3::Applied0<F, A, B, C, D>where F: FnOnce(A, B, C) -> D,

§

type Ret = Curry3<F, Just<A>, Nothing<B>, Nothing<C>, D>

source§

impl<F, A, B, C, D> F1Once<B> for naan::fun::curry3::Applied1<F, A, B, C, D>where F: FnOnce(A, B, C) -> D,

§

type Ret = Curry3<F, Just<A>, Just<B>, Nothing<C>, D>

source§

impl<F, A, B, C, D> F1Once<C> for Applied2<F, A, B, C, D>where F: FnOnce(A, B, C) -> D,

§

type Ret = D

source§

impl<F, G, A, X, C> F1Once<A> for Compose<F, G, X>where F: F1Once<A, Ret = X>, G: F1Once<X, Ret = C>,

§

type Ret = C