Skip to content

Commit f99c1e5

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

File tree

10 files changed

+231
-7
lines changed

10 files changed

+231
-7
lines changed

deep_causality_haft/src/extensions/hkt_option_ext.rs

Lines changed: 14 additions & 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 crate::{Applicative, Functor, HKT, Monad};
6+
use crate::{Applicative, Foldable, Functor, HKT, Monad};
77

88
// Witness for Option
99
pub struct OptionWitness;
@@ -42,6 +42,19 @@ impl Applicative<OptionWitness> for OptionWitness {
4242
}
4343
}
4444

45+
// Implementation of Foldable for OptionWitness
46+
impl Foldable<OptionWitness> for OptionWitness {
47+
fn fold<A, B, Func>(fa: Option<A>, init: B, mut f: Func) -> B
48+
where
49+
Func: FnMut(B, A) -> B,
50+
{
51+
match fa {
52+
Some(a) => f(init, a),
53+
None => init,
54+
}
55+
}
56+
}
57+
4558
// Implementation of Monad for OptionWitness
4659
impl Monad<OptionWitness> for OptionWitness {
4760
fn bind<A, B, Func>(

deep_causality_haft/src/extensions/hkt_result_ext.rs

Lines changed: 17 additions & 1 deletion
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::{Applicative, Functor, HKT, HKT2, Monad, Placeholder};
5+
use crate::{Applicative, Foldable, Functor, HKT, HKT2, Monad, Placeholder};
66

77
// Witness for Result<T, E> where E is fixed
88
pub struct ResultWitness<E>(Placeholder, E);
@@ -57,6 +57,22 @@ where
5757
}
5858
}
5959

60+
// Implementation of Foldable for ResultWitness
61+
impl<E> Foldable<ResultWitness<E>> for ResultWitness<E>
62+
where
63+
E: 'static,
64+
{
65+
fn fold<A, B, Func>(fa: Result<A, E>, init: B, mut f: Func) -> B
66+
where
67+
Func: FnMut(B, A) -> B,
68+
{
69+
match fa {
70+
Ok(a) => f(init, a),
71+
Err(_) => init,
72+
}
73+
}
74+
}
75+
6076
// Implementation of Monad for ResultWitness
6177
impl<E> Monad<ResultWitness<E>> for ResultWitness<E>
6278
where

deep_causality_haft/src/extensions/hkt_vec_ext.rs

Lines changed: 12 additions & 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 crate::{Applicative, Functor, HKT, Monad};
6+
use crate::{Applicative, Foldable, Functor, HKT, Monad};
77

88
// Witness for Vec<T>
99
pub struct VecWitness;
@@ -46,6 +46,17 @@ impl Applicative<VecWitness> for VecWitness {
4646
}
4747
}
4848

49+
// Implementation of Foldable for VecWitness
50+
impl Foldable<VecWitness> for VecWitness {
51+
fn fold<A, B, Func>(fa: <VecWitness as HKT>::Type<A>, init: B, f: Func) -> B
52+
where
53+
<VecWitness as HKT>::Type<A>: IntoIterator<Item = A>,
54+
Func: FnMut(B, A) -> B,
55+
{
56+
fa.into_iter().fold(init, f)
57+
}
58+
}
59+
4960
// Implementation of Monad for VecWitness
5061
impl Monad<VecWitness> for VecWitness {
5162
fn bind<A, B, Func>(m_a: <VecWitness as HKT>::Type<A>, f: Func) -> <VecWitness as HKT>::Type<B>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
use crate::HKT;
6+
7+
/// Foldable: Abstracts over types that can be reduced to a single summary value.
8+
///
9+
/// Generic over the HKT witness `F`.
10+
pub trait Foldable<F: HKT> {
11+
/// Reduces the elements of the structure to a single value by applying a function.
12+
///
13+
/// This is equivalent to a left-fold (foldl) operation.
14+
fn fold<A, B, Func>(fa: F::Type<A>, init: B, f: Func) -> B
15+
where
16+
Func: FnMut(B, A) -> B;
17+
}

deep_causality_haft/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod applicative;
22
mod effect;
33
mod extensions;
4+
mod foldable;
45
mod functor;
56
mod hkt;
67
mod monad;
@@ -12,7 +13,10 @@ pub use crate::effect::{Effect3, Effect4, Effect5};
1213
pub use crate::extensions::hkt_option_ext::OptionWitness;
1314
pub use crate::extensions::hkt_result_ext::ResultWitness;
1415
pub use crate::extensions::hkt_vec_ext::VecWitness;
16+
pub use crate::foldable::Foldable;
1517
pub use crate::functor::Functor;
1618
pub use crate::hkt::{HKT, HKT2, HKT3, HKT4, HKT5, Placeholder};
1719
pub use crate::monad::Monad;
1820
pub use crate::monad_effect::{MonadEffect3, MonadEffect4, MonadEffect5};
21+
22+
// Traversable

deep_causality_haft/tests/extensions/hkt_option_ext_tests.rs

Lines changed: 27 additions & 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::{Applicative, Functor, HKT, Monad, OptionWitness};
6+
use deep_causality_haft::{Applicative, Foldable, Functor, HKT, Monad, OptionWitness};
77

88
// --- Applicative Tests ---
99

@@ -37,6 +37,32 @@ fn test_applicative_option_apply_none_val() {
3737
assert_eq!(result, None);
3838
}
3939

40+
// --- Foldable Tests ---
41+
42+
#[test]
43+
fn test_foldable_option_some() {
44+
let opt = Some(5);
45+
let result = OptionWitness::fold(opt, 0, |acc, x| acc + x);
46+
assert_eq!(result, 5);
47+
}
48+
49+
#[test]
50+
fn test_foldable_option_none() {
51+
let opt: Option<i32> = None;
52+
let result = OptionWitness::fold(opt, 0, |acc, x| acc + x);
53+
assert_eq!(result, 0);
54+
}
55+
56+
#[test]
57+
fn test_foldable_option_string_concat() {
58+
let opt = Some("hello".to_string());
59+
let result = OptionWitness::fold(opt, String::new(), |mut acc, x| {
60+
acc.push_str(&x);
61+
acc
62+
});
63+
assert_eq!(result, "hello");
64+
}
65+
4066
// --- HKT Tests ---
4167

4268
#[test]

deep_causality_haft/tests/extensions/hkt_result_ext_tests.rs

Lines changed: 27 additions & 1 deletion
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 deep_causality_haft::{Applicative, Functor, HKT, HKT2, Monad, ResultWitness};
5+
use deep_causality_haft::{Applicative, Foldable, Functor, HKT, HKT2, Monad, ResultWitness};
66

77
// --- Applicative Tests ---
88

@@ -36,6 +36,32 @@ fn test_applicative_result_apply_err_val() {
3636
assert_eq!(result, Err("Value Error".to_string()));
3737
}
3838

39+
// --- Foldable Tests ---
40+
41+
#[test]
42+
fn test_foldable_result_ok() {
43+
let res: Result<i32, String> = Ok(5);
44+
let result = ResultWitness::fold(res, 0, |acc, x| acc + x);
45+
assert_eq!(result, 5);
46+
}
47+
48+
#[test]
49+
fn test_foldable_result_err() {
50+
let res: Result<i32, String> = Err("error".to_string());
51+
let result = ResultWitness::fold(res, 0, |acc, x| acc + x);
52+
assert_eq!(result, 0);
53+
}
54+
55+
#[test]
56+
fn test_foldable_result_string_concat() {
57+
let res: Result<String, String> = Ok("world".to_string());
58+
let result = ResultWitness::fold(res, String::new(), |mut acc, x| {
59+
acc.push_str(&x);
60+
acc
61+
});
62+
assert_eq!(result, "world");
63+
}
64+
3965
// --- HKT Tests ---
4066

4167
#[test]

deep_causality_haft/tests/extensions/hkt_vec_ext_tests.rs

Lines changed: 27 additions & 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::{Applicative, Functor, HKT, Monad, VecWitness};
6+
use deep_causality_haft::{Applicative, Foldable, Functor, HKT, Monad, VecWitness};
77

88
// --- Applicative Tests ---
99

@@ -38,6 +38,32 @@ fn test_applicative_vec_apply_empty_val() {
3838
assert_eq!(result, Vec::<i32>::new());
3939
}
4040

41+
// --- Foldable Tests ---
42+
43+
#[test]
44+
fn test_foldable_vec_non_empty() {
45+
let vec = vec![1, 2, 3];
46+
let result = VecWitness::fold(vec, 0, |acc, x| acc + x);
47+
assert_eq!(result, 6);
48+
}
49+
50+
#[test]
51+
fn test_foldable_vec_empty() {
52+
let vec: Vec<i32> = Vec::new();
53+
let result = VecWitness::fold(vec, 0, |acc, x| acc + x);
54+
assert_eq!(result, 0);
55+
}
56+
57+
#[test]
58+
fn test_foldable_vec_string_concat() {
59+
let vec = vec!["hello".to_string(), " ".to_string(), "world".to_string()];
60+
let result = VecWitness::fold(vec, String::new(), |mut acc, x| {
61+
acc.push_str(&x);
62+
acc
63+
});
64+
assert_eq!(result, "hello world");
65+
}
66+
4167
// --- HKT Tests ---
4268

4369
#[test]
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
6+
use deep_causality_haft::{Foldable, OptionWitness, ResultWitness, VecWitness};
7+
8+
// --- OptionWitness Foldable Tests ---
9+
10+
#[test]
11+
fn test_foldable_option_some() {
12+
let opt = Some(5);
13+
let result = OptionWitness::fold(opt, 0, |acc, x| acc + x);
14+
assert_eq!(result, 5);
15+
}
16+
17+
#[test]
18+
fn test_foldable_option_none() {
19+
let opt: Option<i32> = None;
20+
let result = OptionWitness::fold(opt, 0, |acc, x| acc + x);
21+
assert_eq!(result, 0);
22+
}
23+
24+
#[test]
25+
fn test_foldable_option_string_concat() {
26+
let opt = Some("hello".to_string());
27+
let result = OptionWitness::fold(opt, String::new(), |mut acc, x| {
28+
acc.push_str(&x);
29+
acc
30+
});
31+
assert_eq!(result, "hello");
32+
}
33+
34+
// --- ResultWitness Foldable Tests ---
35+
36+
#[test]
37+
fn test_foldable_result_ok() {
38+
let res: Result<i32, String> = Ok(5);
39+
let result = ResultWitness::fold(res, 0, |acc, x| acc + x);
40+
assert_eq!(result, 5);
41+
}
42+
43+
#[test]
44+
fn test_foldable_result_err() {
45+
let res: Result<i32, String> = Err("error".to_string());
46+
let result = ResultWitness::fold(res, 0, |acc, x| acc + x);
47+
assert_eq!(result, 0);
48+
}
49+
50+
#[test]
51+
fn test_foldable_result_string_concat() {
52+
let res: Result<String, String> = Ok("world".to_string());
53+
let result = ResultWitness::fold(res, String::new(), |mut acc, x| {
54+
acc.push_str(&x);
55+
acc
56+
});
57+
assert_eq!(result, "world");
58+
}
59+
60+
// --- VecWitness Foldable Tests ---
61+
62+
#[test]
63+
fn test_foldable_vec_non_empty() {
64+
let vec = vec![1, 2, 3];
65+
let result = VecWitness::fold(vec, 0, |acc, x| acc + x);
66+
assert_eq!(result, 6);
67+
}
68+
69+
#[test]
70+
fn test_foldable_vec_empty() {
71+
let vec: Vec<i32> = Vec::new();
72+
let result = VecWitness::fold(vec, 0, |acc, x| acc + x);
73+
assert_eq!(result, 0);
74+
}
75+
76+
#[test]
77+
fn test_foldable_vec_string_concat() {
78+
let vec = vec!["hello".to_string(), " ".to_string(), "world".to_string()];
79+
let result = VecWitness::fold(vec, String::new(), |mut acc, x| {
80+
acc.push_str(&x);
81+
acc
82+
});
83+
assert_eq!(result, "hello world");
84+
}

deep_causality_haft/tests/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
*/
55

66
mod extensions;
7-
7+
#[cfg(test)]
8+
mod foldable_tests;
89
#[cfg(test)]
910
mod hkt_tests;
1011
#[cfg(test)]

0 commit comments

Comments
 (0)