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
234
235
236
237
238
239
240
241
242
243
pub mod hkt {
//! # Higher-Kinded Type (HKT) Apply
//!
//! This module defines the `Apply` trait for HKTs, which extends `Functor`.
//! `Apply` provides the `apply` method (often denoted as `<*>`), allowing sequential
//! application of a wrapped function to a wrapped value.
//!
//! If you have `F<A>` (a wrapped value) and `F<A -> B>` (a wrapped function),
//! `apply` combines them to produce `F<B>`.
//!
//! The HKT `Apply` trait is generic over:
//! - `Self`: The HKT marker (e.g., [`OptionHKTMarker`]).
//! - `A`: The input type of the function `A -> B` and the type of value in `Self::Applied<A>`.
//! - `B`: The output type of the function `A -> B` and the type of value in `Self::Applied<B>`.
use crate::function::{CFn, CFnOnce};
use crate::functor::{Functor}; // HKT Functor
use crate::kind_based::kind::{
HKT, HKT1, OptionHKTMarker, VecHKTMarker, ResultHKTMarker, CFnHKTMarker, CFnOnceHKTMarker
};
/// Represents an HKT that can apply a wrapped function to a wrapped value.
///
/// `Self` refers to the HKT marker type (e.g., [`OptionHKTMarker`]) that implements
/// [`HKT1`] and [`Functor`].
///
/// The `apply` method takes `Self::Applied<A>` (e.g., `Option<A>`) and
/// `Self::Applied<CFn<A, B>>` (e.g., `Option<CFn<A, B>>`), and produces
/// `Self::Applied<B>` (e.g., `Option<B>`).
///
/// ## Apply Laws
/// (Often defined in terms of `Applicative` which builds on `Apply`)
/// A key law related to `apply` is compositional:
/// `apply(apply(v, compose_pure_fn), pure_g_fn) == apply(v, apply(pure_f_fn, pure_compose_fn))`
/// where `compose_pure_fn` is `pure(.)` or `pure(|f| |g| |x| f(g(x)))`.
/// More commonly, laws are expressed with `Applicative`.
pub trait Apply<A, B>: Functor<A, B>
where
Self: Sized + HKT1,
A: 'static,
B: 'static,
{
/// Applies a function wrapped in an HKT structure to a value wrapped in the same HKT structure.
///
/// # Type Parameters
/// - `Self`: The HKT marker.
/// - `A`: The input type for the wrapped function `CFn<A, B>`.
/// - `B`: The result type of the wrapped function and the output HKT structure.
///
/// # Parameters
/// - `value_container`: The HKT-structured value `Self::Applied<A>`.
/// - `function_container`: The HKT-structured function `Self::Applied<CFn<A, B>>`.
/// Note: The function itself is wrapped in [`CFn`], which handles dynamic dispatch
/// and necessary `'static` bounds for the function it wraps.
///
/// # Returns
/// A new HKT-structured value `Self::Applied<B>`.
fn apply(
value_container: Self::Applied<A>,
function_container: Self::Applied<CFn<A, B>>,
) -> Self::Applied<B>;
}
impl<A: 'static, B: 'static> Apply<A, B> for OptionHKTMarker {
fn apply(
value_container: Self::Applied<A>,
function_container: Self::Applied<CFn<A, B>>,
) -> Self::Applied<B> {
value_container.and_then(|val_a| function_container.map(|func_ab| func_ab.call(val_a)))
}
}
impl<A: 'static, B: 'static, E: 'static + Clone> Apply<A, B> for ResultHKTMarker<E> {
fn apply(
value_container: Self::Applied<A>,
function_container: Self::Applied<CFn<A, B>>,
) -> Self::Applied<B> {
value_container.and_then(|val_a| function_container.map(|func_ab| func_ab.call(val_a)))
}
}
impl<A: 'static + Clone, B: 'static> Apply<A, B> for VecHKTMarker {
fn apply(
value_container: Self::Applied<A>,
function_container: Self::Applied<CFn<A, B>>,
) -> Self::Applied<B> {
function_container
.into_iter()
.flat_map(|f_fn| {
value_container
.iter()
.map(move |val_a| f_fn.call(val_a.clone()))
})
.collect()
}
}
// Apply for CFnHKTMarker<X>
// F::Applied<A> is CFn<X, A>
// F::Applied<CFn<A, B>> is CFn<X, CFn<A, B>>
// Result is CFn<X, B>
// This implements S f g x = (f x) (g x)
impl<X, A, B> Apply<A, B> for CFnHKTMarker<X>
where
X: 'static + Clone, // Clone for x_val in the closure
A: 'static,
B: 'static,
Self: Functor<A, B>, // Ensure Functor constraint is met
Self: HKT<Applied<A> = CFn<X, A>>,
Self: HKT<Applied<CFn<A, B>> = CFn<X, CFn<A, B>>>,
Self: HKT<Applied<B> = CFn<X, B>>,
// Removed: CFn<X, CFn<A, B>>: Fn(X) -> CFn<A, B>,
// Removed: CFn<X, A>: Fn(X) -> A,
// The .call method on CFn struct does not require CFn itself to be Fn.
// A: 'static is from Apply trait. X: 'static + Clone for closure. B: 'static from Apply trait.
{
fn apply(
value_container: Self::Applied<A>, // This is c_x_a
function_container: Self::Applied<CFn<A, B>>, // This is c_x_fab
) -> Self::Applied<B> {
// Self::Applied<A> is CFn<X, A>
// Self::Applied<CFn<A, B>> is CFn<X, CFn<A, B>>
CFn::new(move |x_val: X| {
let func_ab = function_container.call(x_val.clone());
let val_a = value_container.call(x_val);
func_ab.call(val_a)
})
}
}
// Apply for CFnOnceHKTMarker<X>
// Similar to CFnHKTMarker, but uses call_once and produces CFnOnce
impl<X, A, B> Apply<A, B> for CFnOnceHKTMarker<X>
where
X: 'static + Clone, // Clone for x_val in the closure
A: 'static,
B: 'static,
Self: Functor<A, B>,
Self: HKT<Applied<A> = CFnOnce<X, A>>,
Self: HKT<Applied<CFn<A, B>> = CFnOnce<X, CFn<A, B>>>, // Assuming the function container holds CFn<A,B>
Self: HKT<Applied<B> = CFnOnce<X, B>>,
// Removed FnOnce bounds on GATs. The .call_once method is inherent.
// <Self as HKT>::Applied<CFn<A, B>>: FnOnce(X) -> CFn<A, B>,
// <Self as HKT>::Applied<A>: FnOnce(X) -> A,
// A: 'static from Apply trait. X: 'static + Clone for closure. B: 'static from Apply trait.
// For now, let's assume CFn<A,B> can be called via call_once if it's the last use.
// The compiler error E0599 for call_once on CFnOnceHKTMarker::Applied<CFn<A,B>>
// indicates that the GAT itself needs to satisfy FnOnce(X) -> CFn<A,B>.
// And for CFnOnceHKTMarker::Applied<A>, it needs FnOnce(X) -> A.
// The inner func_ab.call_once(val_a) implies CFn<A,B>: FnOnce(A) -> B.
// CFn already implements Fn, FnMut, and FnOnce if the inner Box<dyn Fn...> does.
// The issue is that the GAT Self::Applied<CFn<A,B>> is opaque.
{
fn apply(
value_container: Self::Applied<A>, // CFnOnce<X,A>
function_container: Self::Applied<CFn<A, B>>, // CFnOnce<X, CFn<A,B>>
) -> Self::Applied<B> { // CFnOnce<X,B>
CFnOnce::new(move |x_val: X| {
// Self::Applied<CFn<A,B>> is CFnOnce<X, CFn<A,B>>
// Self::Applied<A> is CFnOnce<X,A>
let func_ab = function_container.call_once(x_val.clone()); // func_ab is CFn<A,B>
let val_a = value_container.call_once(x_val); // val_a is A
func_ab.call(val_a) // Changed to .call(val_a) from .call_once((val_a,))
})
}
}
/// Lifts a binary curried function to operate on HKT contexts.
///
/// Given `func: A -> (B -> C)` (represented as `A -> CFn<B, C>`),
/// `fa: F<A>`, and `fb: F<B>`, `lift2` produces `F<C>`.
/// It's equivalent to `apply(map(fa, func), fb)` but expressed using the `Apply` trait's `apply` method.
pub fn lift2<F, A, B, C, FuncImpl>(
func: FuncImpl, // A -> CFn<B, C>
fa: F::Applied<A>,
fb: F::Applied<B>,
) -> F::Applied<C>
where
F: Apply<B, C> + Functor<A, CFn<B, C>> + HKT1,
FuncImpl: Fn(A) -> CFn<B, C> + Clone + 'static,
A: 'static, B: 'static, C: 'static,
{
let f_b_to_c_in_f = F::map(fa, func);
F::apply(fb, f_b_to_c_in_f)
}
/// Lifts a ternary curried function to operate on HKT contexts.
///
/// Given `func: A -> (B -> (C -> D))` (represented as `A -> CFn<B, CFn<C, D>>`),
/// `fa: F<A>`, `fb: F<B>`, and `fc: F<C>`, `lift3` produces `F<D>`.
pub fn lift3<F, A, B, C, D, FuncImpl>(
func: FuncImpl, // A -> CFn<B, CFn<C, D>>
fa: F::Applied<A>,
fb: F::Applied<B>,
fc: F::Applied<C>,
) -> F::Applied<D>
where
F: Apply<C, D>
+ Apply<B, CFn<C,D>>
+ Functor<A, CFn<B, CFn<C,D>>>
+ HKT1,
FuncImpl: Fn(A) -> CFn<B, CFn<C, D>> + Clone + 'static,
A: 'static, B: 'static, C: 'static, D: 'static,
{
let f_b_to_c_to_d_in_f = F::map(fa, func);
let f_c_to_d_in_f = <F as Apply<B, CFn<C,D>>>::apply(fb, f_b_to_c_to_d_in_f);
<F as Apply<C,D>>::apply(fc, f_c_to_d_in_f)
}
/// Combines two HKT actions, keeping only the result of the first.
/// Often denoted as `<*`.
pub fn apply_first<F, A, B>(
fa: F::Applied<A>,
fb: F::Applied<B>,
) -> F::Applied<A>
where
F: Apply<B, A> + Functor<A, CFn<B, A>> + HKT1,
A: Copy + 'static,
B: 'static,
{
let map_fn = |x: A| CFn::new(move |_y: B| x);
lift2::<F, A, B, A, _>(map_fn, fa, fb)
}
/// Combines two HKT actions, keeping only the result of the second.
/// Often denoted as `*>`.
pub fn apply_second<F, A, B>(
fa: F::Applied<A>,
fb: F::Applied<B>,
) -> F::Applied<B>
where
F: Apply<B, B> + Functor<A, CFn<B, B>> + HKT1,
A: 'static,
B: Copy + 'static,
{
let map_fn = |_: A| CFn::new(|y: B| y);
lift2::<F, A, B, B, _>(map_fn, fa, fb)
}
}
// Directly export HKT Apply and related functions
pub use hkt::*;