1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
pub mod hkt {
//! # Higher-Kinded Type (HKT) Applicative Functor
//!
//! This module defines the `Applicative` trait for HKTs, which extends `Apply`.
//! An Applicative Functor allows lifting a normal value into the HKT context
//! (via `pure`) and applying a wrapped function to a wrapped value (via `apply`
//! from the `Apply` supertrait).
//!
//! The HKT `Applicative` trait is generic over:
//! - `Self`: The HKT marker (e.g., [`OptionHKTMarker`]).
//! - `T`: The type of the value being lifted by `pure`.
//!
//! ## Example
//!
//! ```
//! use monadify::applicative::hkt::{Applicative, lift_a1}; // Applicative for ::pure
//! use monadify::apply::hkt::Apply; // for .apply() method
//! use monadify::kind_based::kind::OptionHKTMarker;
//! use monadify::function::CFn;
//!
//! // Using pure and apply directly
//! let val_opt: Option<i32> = OptionHKTMarker::pure(10); // Some(10)
//! let fn_opt: Option<CFn<i32, i32>> = OptionHKTMarker::pure(CFn::new(|x| x + 1)); // Some(CFn)
//!
//! // Need to specify the marker for apply
//! let result_opt: Option<i32> = OptionHKTMarker::apply(val_opt, fn_opt);
//! assert_eq!(result_opt, Some(11));
//!
//! // Using lift_a1 (which uses pure and apply internally)
//! let val_opt2: Option<i32> = Some(20);
//! // Specify the HKT marker for lift_a1 if it cannot be inferred
//! let result_opt2: Option<i32> = lift_a1::<OptionHKTMarker, _, _, _>(|x: i32| x * 2, val_opt2);
//! assert_eq!(result_opt2, Some(40));
//! ```
//!
//! `Applicative` builds upon `Apply` by adding the `pure` method. This allows
//! functions and values to be lifted into the context before application.
//! A common pattern, often called `lift_a1` or similar, is equivalent to
//! `map` from `Functor` but implemented using `pure` and `apply`:
//! `map f fa == apply(fa, pure(f))`. Note: The order of arguments in `apply` can vary;
//! this library's `apply` takes `(value_context, function_context)`.
//! The `lift_a1` function in this module demonstrates this pattern.
use crate::apply::hkt::Apply; // HKT Apply
use crate::function::{CFn, CFnOnce};
use crate::kind_based::kind::{
HKT, HKT1, OptionHKTMarker, ResultHKTMarker, VecHKTMarker, CFnHKTMarker, CFnOnceHKTMarker
};
/// Represents an HKT that is an Applicative Functor.
///
/// `Self` refers to the HKT marker type (e.g., [`OptionHKTMarker`]) that implements
/// [`HKT1`] and [`Apply`].
///
/// The primary method provided by `Applicative` is `pure`, which takes a regular
/// value `T` and lifts it into the HKT context, producing `Self::Applied<T>`
/// (e.g., `pure(10)` for `OptionHKTMarker` yields `Some(10)`).
///
/// ## Example of `pure`
///
/// ```
/// use monadify::applicative::hkt::Applicative;
/// use monadify::kind_based::kind::{OptionHKTMarker, VecHKTMarker};
///
/// // For Option
/// let val_opt: Option<i32> = OptionHKTMarker::pure(10);
/// assert_eq!(val_opt, Some(10));
///
/// // For Vec (requires T: Clone for pure)
/// let val_vec: Vec<String> = VecHKTMarker::pure("hello".to_string());
/// assert_eq!(val_vec, vec!["hello".to_string()]);
/// ```
///
/// ## Applicative Laws
/// Implementors must satisfy several laws:
/// 1. **Identity**: `apply(v, pure(identity_fn)) == v`
/// 2. **Homomorphism**: `apply(pure(x), pure(f_fn)) == pure(f(x))`
/// 3. **Interchange**: `apply(pure(y), u) == apply(u, pure(|f_fn| f_fn(y)))`
/// 4. **Composition (derived)**: `map f x == apply(x, pure(f))` (often shown as `lift_a1`)
/// (Note: The exact formulation of composition can vary, often involving `apply` and `pure`.)
pub trait Applicative<T>: Apply<T, T>
where
Self: Sized + HKT1,
T: 'static,
{
/// Lifts a value into the applicative context.
///
/// # Parameters
/// - `value`: The value of type `T` to be lifted.
/// The `T: 'static` bound is common. Many `pure` implementations also require `T: Clone`
/// (e.g., for [`CFnHKTMarker`], [`VecHKTMarker`]) if the `value` needs to be cloned
/// into the new context, especially if the context itself might be "called" or
/// iterated multiple times. This can make some applicative laws involving `pure`
/// of non-`Clone` function types (like `CFn`) untestable.
///
/// # Returns
/// The value wrapped in the HKT applicative structure, `Self::Applied<T>`.
fn pure(value: T) -> Self::Applied<T>;
}
impl<T: 'static> Applicative<T> for OptionHKTMarker {
/// Lifts a value `T` into [`Some(T)`].
fn pure(value: T) -> Self::Applied<T> { // Self::Applied<T> is Option<T>
Some(value)
}
}
impl<T: 'static, E: 'static + Clone> Applicative<T> for ResultHKTMarker<E> {
/// Lifts a value `T` into [`Ok(T)`].
fn pure(value: T) -> Self::Applied<T> { // Self::Applied<T> is Result<T, E>
Ok(value)
}
}
impl<T: 'static + Clone> Applicative<T> for VecHKTMarker {
/// Lifts a value `T` into `vec![T]`.
///
/// The `T: Clone` bound on this `impl` block is due to `Vec`'s `pure`
/// creating a new vector with the element.
fn pure(value: T) -> Self::Applied<T> { // Self::Applied<T> is Vec<T>
vec![value]
}
}
// Applicative for CFnHKTMarker
// Lifts a value `T` into `CFn<X, T>` which always returns `value.clone()`
impl<X, T> Applicative<T> for CFnHKTMarker<X>
where
X: 'static,
T: 'static + Clone, // T needs to be Clone for the closure
Self: Apply<T,T>, // Ensure Apply<T,T> for CFnHKTMarker<X> is defined
Self: HKT<Applied<T> = CFn<X, T>>, // Explicitly state the GAT equality
{
/// Lifts a value `T` into a `CFn<X, T>` (a function `X -> T`).
///
/// The resulting function, when called with any input of type `X`,
/// will ignore that input and always return a clone of the original `value`.
///
/// Requires `T: Clone` because the lifted value is cloned by the returned function.
fn pure(value: T) -> Self::Applied<T> {
// Self::Applied<T> is CFn<X, T> as per HKT1 impl for CFnHKTMarker
CFn::new(move |_x: X| value.clone())
}
}
// Applicative for CFnOnceHKTMarker
// Lifts a value `T` into `CFnOnce<X, T>`
impl<X, T> Applicative<T> for CFnOnceHKTMarker<X>
where
X: 'static,
T: 'static + Clone,
Self: Apply<T,T>,
Self: HKT<Applied<T> = CFnOnce<X, T>>, // Explicitly state the GAT equality
{
/// Lifts a value `T` into a `CFnOnce<X, T>` (a function `X -> T` called once).
///
/// The resulting function, when called with any input of type `X`,
/// will ignore that input and return a clone of the original `value`.
///
/// Requires `T: Clone` as the lifted value is cloned by the returned function.
fn pure(value: T) -> Self::Applied<T> {
// Self::Applied<T> is CFnOnce<X, T> as per HKT1 impl for CFnOnceHKTMarker
CFnOnce::new(move |_x: X| value.clone())
}
}
/// Lifts a unary function `A -> B` to operate on HKT `Applicative` values: `F<A> -> F<B>`.
/// This is `map` defined via `pure` and `apply`: `map f fa == apply(fa, pure(CFn::new(f)))`.
///
/// # Parameters
/// - `F`: The HKT marker, must implement `Applicative<CFn<A,B>>` and `Apply<A,B>`.
/// - `func`: The function `A -> B`.
/// - `fa`: The applicative value `F::Applied<A>`.
///
/// # Returns
/// The result `F::Applied<B>`.
///
/// ## Example
///
/// ```
/// use monadify::applicative::hkt::lift_a1;
/// use monadify::kind_based::kind::{OptionHKTMarker, VecHKTMarker}; // For context type
///
/// // Using lift_a1 with Option
/// let opt_val: Option<i32> = Some(5);
/// // Provide the HKT marker via turbofish if type inference needs help
/// let lifted_opt: Option<String> = lift_a1::<OptionHKTMarker, _, _, _>(
/// |x: i32| (x * 2).to_string(),
/// opt_val
/// );
/// assert_eq!(lifted_opt, Some("10".to_string()));
///
/// // Using lift_a1 with Vec
/// // Note: This example would fail if `CFn` needed to be cloned by `Applicative::pure`
/// // for `VecHKTMarker`, as `CFn` is not `Clone`.
/// // The current `lift_a1` requires `F: Applicative<CFn<A, B>>`.
/// // `VecHKTMarker`'s `Applicative<T>` impl requires `T: Clone`.
/// // Thus, `VecHKTMarker` needs `Applicative<CFn<A,B>>` where `CFn<A,B>: Clone`.
/// // Since `CFn` is not `Clone`, this specific example is commented out.
/// /*
/// let vec_val: Vec<i32> = vec![1, 2, 3];
/// let lifted_vec: Vec<bool> = lift_a1::<VecHKTMarker, _, _, _>(
/// |x: i32| x % 2 == 0,
/// vec_val
/// );
/// assert_eq!(lifted_vec, vec![false, true, false]);
/// */
/// ```
pub fn lift_a1<F, A, B, FuncImpl>(
func: FuncImpl,
fa: F::Applied<A>,
) -> F::Applied<B>
where
F: Applicative<CFn<A, B>> + Apply<A, B> + HKT1,
FuncImpl: Fn(A) -> B + 'static,
A: 'static,
B: 'static,
CFn<A, B>: 'static, // Ensure the lifted function type is 'static
{
// 1. Lift the function `func: A -> B` into the context using `CFn`.
// `F::pure(CFn::new(func))` results in `F::Applied<CFn<A, B>>`.
// This requires `F` to be `Applicative` for the type `CFn<A, B>`.
let f_in_context: F::Applied<CFn<A, B>> = F::pure(CFn::new(func));
// 2. Apply the wrapped function to the wrapped value.
// `F::apply(fa, f_in_context)` where `fa` is `F::Applied<A>`.
// This requires `F` to be `Apply<A, B>`.
F::apply(fa, f_in_context)
}
}
// Directly export HKT Applicative and related functions
pub use hkt::*;