Skip to content

Commit c615c5c

Browse files
committed
feat(deep_causality_haft): Added Applicative trait with tests.
Signed-off-by: Marvin Hansen <[email protected]>
1 parent 591dcb8 commit c615c5c

File tree

13 files changed

+324
-26
lines changed

13 files changed

+324
-26
lines changed

deep_causality_haft/examples/simple_haft.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
44
*/
55

6-
use deep_causality_haft::{Functor, Monad, OptionWitness, ResultWitness};
6+
use deep_causality_haft::{Applicative, Functor, Monad, OptionWitness, ResultWitness};
77

88
fn main() {
99
println!("--- Option Example ---");
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
use crate::{Functor, HKT};
6+
7+
/// Applicative: Abstracts over the ability to apply a function wrapped in a context
8+
/// to a value wrapped in a context.
9+
///
10+
/// Generic over the HKT witness `F`.
11+
pub trait Applicative<F: HKT>: Functor<F> {
12+
/// Lifts a pure value into the minimal applicative context.
13+
fn pure<T>(value: T) -> F::Type<T>;
14+
15+
/// Applies a function wrapped in a context to a value wrapped in a context.
16+
fn apply<A, B, Func>(f_ab: F::Type<Func>, f_a: F::Type<A>) -> F::Type<B>
17+
where
18+
Func: FnMut(A) -> B,
19+
A: Clone;
20+
}

deep_causality_haft/src/extensions/hkt_option_ext.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
44
*/
55

6-
use crate::{Functor, HKT, Monad};
6+
use crate::{Applicative, Functor, HKT, Monad};
77

88
// Witness for Option
99
pub struct OptionWitness;
@@ -25,12 +25,25 @@ impl Functor<OptionWitness> for OptionWitness {
2525
}
2626
}
2727

28-
// Implementation of Monad for OptionWitness
29-
impl Monad<OptionWitness> for OptionWitness {
28+
// Implementation of Applicative for OptionWitness
29+
impl Applicative<OptionWitness> for OptionWitness {
3030
fn pure<T>(value: T) -> <OptionWitness as HKT>::Type<T> {
3131
Some(value)
3232
}
3333

34+
fn apply<A, B, Func>(
35+
f_ab: <OptionWitness as HKT>::Type<Func>,
36+
f_a: <OptionWitness as HKT>::Type<A>,
37+
) -> <OptionWitness as HKT>::Type<B>
38+
where
39+
Func: FnMut(A) -> B,
40+
{
41+
f_ab.and_then(|f| f_a.map(f))
42+
}
43+
}
44+
45+
// Implementation of Monad for OptionWitness
46+
impl Monad<OptionWitness> for OptionWitness {
3447
fn bind<A, B, Func>(
3548
m_a: <OptionWitness as HKT>::Type<A>,
3649
f: Func,

deep_causality_haft/src/extensions/hkt_result_ext.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SPDX-License-Identifier: MIT
33
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
44
*/
5-
use crate::{Functor, HKT, HKT2, Monad, Placeholder};
5+
use crate::{Applicative, Functor, HKT, HKT2, Monad, Placeholder};
66

77
// Witness for Result<T, E> where E is fixed
88
pub struct ResultWitness<E>(Placeholder, E);
@@ -31,15 +31,37 @@ where
3131
}
3232
}
3333

34-
// Implementation of Monad for ResultWitness
35-
impl<E> Monad<ResultWitness<E>> for ResultWitness<E>
34+
// Implementation of Applicative for ResultWitness
35+
impl<E> Applicative<ResultWitness<E>> for ResultWitness<E>
3636
where
37-
E: 'static,
37+
E: 'static + Clone,
3838
{
3939
fn pure<T>(value: T) -> <ResultWitness<E> as HKT2<E>>::Type<T> {
4040
Ok(value)
4141
}
4242

43+
fn apply<A, B, Func>(
44+
f_ab: <ResultWitness<E> as HKT2<E>>::Type<Func>,
45+
f_a: <ResultWitness<E> as HKT2<E>>::Type<A>,
46+
) -> <ResultWitness<E> as HKT2<E>>::Type<B>
47+
where
48+
Func: FnMut(A) -> B,
49+
{
50+
match f_ab {
51+
Ok(mut f) => match f_a {
52+
Ok(a) => Ok(f(a)),
53+
Err(e) => Err(e),
54+
},
55+
Err(e) => Err(e),
56+
}
57+
}
58+
}
59+
60+
// Implementation of Monad for ResultWitness
61+
impl<E> Monad<ResultWitness<E>> for ResultWitness<E>
62+
where
63+
E: 'static + Clone,
64+
{
4365
fn bind<A, B, Func>(
4466
m_a: <ResultWitness<E> as HKT2<E>>::Type<A>,
4567
f: Func,

deep_causality_haft/src/extensions/hkt_vec_ext.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
44
*/
55

6-
use crate::{Functor, HKT, Monad};
6+
use crate::{Applicative, Functor, HKT, Monad};
77

88
// Witness for Vec<T>
99
pub struct VecWitness;
@@ -22,12 +22,32 @@ impl Functor<VecWitness> for VecWitness {
2222
}
2323
}
2424

25-
// Implementation of Monad for VecWitness
26-
impl Monad<VecWitness> for VecWitness {
25+
// Implementation of Applicative for VecWitness
26+
impl Applicative<VecWitness> for VecWitness {
2727
fn pure<T>(value: T) -> <VecWitness as HKT>::Type<T> {
2828
vec![value]
2929
}
3030

31+
fn apply<A, B, Func>(
32+
f_ab: <VecWitness as HKT>::Type<Func>,
33+
f_a: <VecWitness as HKT>::Type<A>,
34+
) -> <VecWitness as HKT>::Type<B>
35+
where
36+
Func: FnMut(A) -> B,
37+
A: Clone,
38+
{
39+
f_ab.into_iter()
40+
.flat_map(|mut f_val| {
41+
f_a.iter()
42+
.map(move |a_val| f_val(a_val.clone()))
43+
.collect::<Vec<B>>()
44+
}) // Clone a_val for FnMut
45+
.collect()
46+
}
47+
}
48+
49+
// Implementation of Monad for VecWitness
50+
impl Monad<VecWitness> for VecWitness {
3151
fn bind<A, B, Func>(m_a: <VecWitness as HKT>::Type<A>, f: Func) -> <VecWitness as HKT>::Type<B>
3252
where
3353
Func: FnMut(A) -> <VecWitness as HKT>::Type<B>,

deep_causality_haft/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod applicative;
12
mod effect;
23
mod extensions;
34
mod functor;
@@ -6,6 +7,7 @@ mod monad;
67
mod monad_effect;
78
pub mod utils_tests;
89

10+
pub use crate::applicative::Applicative;
911
pub use crate::effect::{Effect3, Effect4, Effect5};
1012
pub use crate::extensions::hkt_option_ext::OptionWitness;
1113
pub use crate::extensions::hkt_result_ext::ResultWitness;

deep_causality_haft/src/monad.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@
22
* SPDX-License-Identifier: MIT
33
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
44
*/
5-
use crate::{Functor, HKT};
5+
use crate::{Applicative, HKT};
66

77
/// Monad: Abstracts over the ability to sequence computations within a type constructor.
88
///
99
/// Generic over the HKT witness `F`.
10-
pub trait Monad<F: HKT>: Functor<F> {
11-
/// Lifts a value into the minimal monadic context. (e.g., Some(value), Ok(value)).
12-
fn pure<T>(value: T) -> F::Type<T>;
13-
10+
pub trait Monad<F: HKT>: Applicative<F> {
1411
/// Chains a computation from an effectful value, flattening the result.
1512
/// This is the core sequencing operation.
1613
fn bind<A, B, Func>(m_a: F::Type<A>, f: Func) -> F::Type<B>

deep_causality_haft/src/monad_effect.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,18 @@ where
5858
/// Monadic logic for the Arity 5 type after it has been partially applied.
5959
///
6060
/// Generic over the Effect5 witness `E`.
61-
///
62-
#[allow(clippy::type_complexity)]
6361
pub trait MonadEffect5<E: Effect5>
6462
where
6563
E::HktWitness: Functor<E::HktWitness> + Sized,
6664
{
6765
/// Lifts a pure value into an Effect container.
66+
#[allow(clippy::type_complexity)]
6867
fn pure<T>(
6968
value: T,
7069
) -> <E::HktWitness as HKT5<E::Fixed1, E::Fixed2, E::Fixed3, E::Fixed4>>::Type<T>;
7170

7271
/// The core sequencing operation
72+
#[allow(clippy::type_complexity)]
7373
fn bind<T, U, Func>(
7474
effect: <E::HktWitness as HKT5<E::Fixed1, E::Fixed2, E::Fixed3, E::Fixed4>>::Type<T>,
7575
f: Func,

deep_causality_haft/src/utils_tests.rs

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
44
*/
55

6-
use crate::{Effect3, Effect4, Effect5, Functor, Monad, MonadEffect3, MonadEffect4, MonadEffect5};
6+
use crate::{
7+
Applicative, Effect3, Effect4, Effect5, Functor, Monad, MonadEffect3, MonadEffect4,
8+
MonadEffect5,
9+
};
710
use crate::{HKT, HKT3, HKT4, HKT5, Placeholder};
811

912
// --- MonadEffect3 Setup ---
@@ -49,7 +52,7 @@ impl Functor<MyEffectHktWitness<String, String>> for MyEffectHktWitness<String,
4952
}
5053
}
5154

52-
impl Monad<MyEffectHktWitness<String, String>> for MyEffectHktWitness<String, String> {
55+
impl Applicative<MyEffectHktWitness<String, String>> for MyEffectHktWitness<String, String> {
5356
fn pure<T>(value: T) -> MyCustomEffectType<T, String, String> {
5457
MyCustomEffectType {
5558
value,
@@ -58,6 +61,40 @@ impl Monad<MyEffectHktWitness<String, String>> for MyEffectHktWitness<String, St
5861
}
5962
}
6063

64+
fn apply<A, B, Func>(
65+
mut f_ab: MyCustomEffectType<Func, String, String>,
66+
f_a: MyCustomEffectType<A, String, String>,
67+
) -> MyCustomEffectType<B, String, String>
68+
where
69+
Func: FnMut(A) -> B,
70+
{
71+
if f_ab.error.is_some() {
72+
return MyCustomEffectType {
73+
value: (f_ab.value)(f_a.value), // Dummy call to satisfy type, actual value discarded
74+
error: f_ab.error,
75+
warnings: f_ab.warnings,
76+
};
77+
}
78+
if f_a.error.is_some() {
79+
return MyCustomEffectType {
80+
value: (f_ab.value)(f_a.value), // Dummy call to satisfy type, actual value discarded
81+
error: f_a.error,
82+
warnings: f_a.warnings,
83+
};
84+
}
85+
86+
let mut combined_warnings = f_ab.warnings;
87+
combined_warnings.extend(f_a.warnings);
88+
89+
MyCustomEffectType {
90+
value: (f_ab.value)(f_a.value),
91+
error: None,
92+
warnings: combined_warnings,
93+
}
94+
}
95+
}
96+
97+
impl Monad<MyEffectHktWitness<String, String>> for MyEffectHktWitness<String, String> {
6198
fn bind<A, B, Func>(
6299
m_a: MyCustomEffectType<A, String, String>,
63100
f: Func,
@@ -188,7 +225,9 @@ impl Functor<MyEffectHktWitness4<String, String, u64>>
188225
}
189226
}
190227

191-
impl Monad<MyEffectHktWitness4<String, String, u64>> for MyEffectHktWitness4<String, String, u64> {
228+
impl Applicative<MyEffectHktWitness4<String, String, u64>>
229+
for MyEffectHktWitness4<String, String, u64>
230+
{
192231
fn pure<T>(value: T) -> MyCustomEffectType4<T, String, String, u64> {
193232
MyCustomEffectType4 {
194233
value,
@@ -198,6 +237,46 @@ impl Monad<MyEffectHktWitness4<String, String, u64>> for MyEffectHktWitness4<Str
198237
}
199238
}
200239

240+
fn apply<A, B, Func>(
241+
mut f_ab: MyCustomEffectType4<Func, String, String, u64>,
242+
f_a: MyCustomEffectType4<A, String, String, u64>,
243+
) -> MyCustomEffectType4<B, String, String, u64>
244+
where
245+
Func: FnMut(A) -> B,
246+
{
247+
if f_ab.f1.is_some() {
248+
return MyCustomEffectType4 {
249+
value: (f_ab.value)(f_a.value), // Dummy call to satisfy type
250+
f1: f_ab.f1,
251+
f2: f_ab.f2,
252+
f3: f_ab.f3,
253+
};
254+
}
255+
if f_a.f1.is_some() {
256+
return MyCustomEffectType4 {
257+
value: (f_ab.value)(f_a.value), // Dummy call to satisfy type
258+
f1: f_a.f1,
259+
f2: f_a.f2,
260+
f3: f_a.f3,
261+
};
262+
}
263+
264+
let mut combined_f2 = f_ab.f2;
265+
combined_f2.extend(f_a.f2);
266+
267+
let mut combined_f3 = f_ab.f3;
268+
combined_f3.extend(f_a.f3);
269+
270+
MyCustomEffectType4 {
271+
value: (f_ab.value)(f_a.value),
272+
f1: None,
273+
f2: combined_f2,
274+
f3: combined_f3,
275+
}
276+
}
277+
}
278+
279+
impl Monad<MyEffectHktWitness4<String, String, u64>> for MyEffectHktWitness4<String, String, u64> {
201280
fn bind<A, B, Func>(
202281
m_a: MyCustomEffectType4<A, String, String, u64>,
203282
f: Func,
@@ -343,7 +422,7 @@ impl Functor<MyEffectHktWitness5<String, String, u64, String>>
343422
}
344423
}
345424

346-
impl Monad<MyEffectHktWitness5<String, String, u64, String>>
425+
impl Applicative<MyEffectHktWitness5<String, String, u64, String>>
347426
for MyEffectHktWitness5<String, String, u64, String>
348427
{
349428
fn pure<T>(value: T) -> MyCustomEffectType5<T, String, String, u64, String> {
@@ -356,6 +435,54 @@ impl Monad<MyEffectHktWitness5<String, String, u64, String>>
356435
}
357436
}
358437

438+
fn apply<A, B, Func>(
439+
mut f_ab: MyCustomEffectType5<Func, String, String, u64, String>,
440+
f_a: MyCustomEffectType5<A, String, String, u64, String>,
441+
) -> MyCustomEffectType5<B, String, String, u64, String>
442+
where
443+
Func: FnMut(A) -> B,
444+
{
445+
if f_ab.f1.is_some() {
446+
return MyCustomEffectType5 {
447+
value: (f_ab.value)(f_a.value), // Dummy call to satisfy type
448+
f1: f_ab.f1,
449+
f2: f_ab.f2,
450+
f3: f_ab.f3,
451+
f4: f_ab.f4,
452+
};
453+
}
454+
if f_a.f1.is_some() {
455+
return MyCustomEffectType5 {
456+
value: (f_ab.value)(f_a.value), // Dummy call to satisfy type
457+
f1: f_a.f1,
458+
f2: f_a.f2,
459+
f3: f_a.f3,
460+
f4: f_a.f4,
461+
};
462+
}
463+
464+
let mut combined_f2 = f_ab.f2;
465+
combined_f2.extend(f_a.f2);
466+
467+
let mut combined_f3 = f_ab.f3;
468+
combined_f3.extend(f_a.f3);
469+
470+
let mut combined_f4 = f_ab.f4;
471+
combined_f4.extend(f_a.f4);
472+
473+
MyCustomEffectType5 {
474+
value: (f_ab.value)(f_a.value),
475+
f1: None,
476+
f2: combined_f2,
477+
f3: combined_f3,
478+
f4: combined_f4,
479+
}
480+
}
481+
}
482+
483+
impl Monad<MyEffectHktWitness5<String, String, u64, String>>
484+
for MyEffectHktWitness5<String, String, u64, String>
485+
{
359486
fn bind<A, B, Func>(
360487
m_a: MyCustomEffectType5<A, String, String, u64, String>,
361488
f: Func,

0 commit comments

Comments
 (0)