fp_library/typeclasses/apply_first.rs
1use crate::hkt::{Apply, Kind};
2
3/// A typeclass for types that support combining two contexts, keeping the first value.
4///
5/// `ApplyFirst` provides the ability to sequence two computations but discard
6/// the result of the second computation, keeping only the result of the first.
7/// This is useful for executing side effects in sequence while preserving the
8/// primary result.
9pub trait ApplyFirst {
10 /// Combines two contexts, keeping the value from the first context.
11 ///
12 /// # Type Signature
13 ///
14 /// `forall f a b. ApplyFirst f => f a -> f b -> f a`
15 ///
16 /// # Parameters
17 ///
18 /// * `fa`: The first context containing a value.
19 /// * `fb`: The second context containing a value (will be discarded).
20 ///
21 /// # Returns
22 ///
23 /// The first context with its value preserved.
24 fn apply_first<A, B>(fa: Apply<Self, (A,)>) -> impl Fn(Apply<Self, (B,)>) -> Apply<Self, (A,)>
25 where
26 Self: Kind<(A,)> + Kind<(B,)>,
27 Apply<Self, (A,)>: Clone,
28 A: Clone,
29 B: Clone;
30}
31
32/// Combines two contexts, keeping the value from the first context.
33///
34/// Free function version that dispatches to [the typeclass method][`ApplyFirst::apply_first`].
35///
36/// # Type Signature
37///
38/// `forall f a b. ApplyFirst f => f a -> f b -> f a`
39///
40/// # Parameters
41///
42/// * `fa`: The first context containing a value.
43/// * `fb`: The second context containing a value (will be discarded).
44///
45/// # Returns
46///
47/// The first context with its value preserved.
48///
49/// # Examples
50///
51/// ```
52/// use fp_library::{brands::OptionBrand, functions::apply_first};
53///
54/// assert_eq!(apply_first::<OptionBrand, _, _>(Some(5))(Some("hello")), Some(5));
55/// ```
56pub fn apply_first<Brand, A, B>(
57 fa: Apply<Brand, (A,)>
58) -> impl Fn(Apply<Brand, (B,)>) -> Apply<Brand, (A,)>
59where
60 Brand: Kind<(A,)> + Kind<(B,)> + ApplyFirst,
61 Apply<Brand, (A,)>: Clone,
62 A: Clone,
63 B: Clone,
64{
65 Brand::apply_first::<A, B>(fa)
66}