Skip to content

Commit da03a2b

Browse files
Merge pull request #359 from marvin-hansen/main
Updated HAFT Crate
2 parents 88ecd07 + 3f050d3 commit da03a2b

38 files changed

+3016
-524
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/scripts/check.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ set -o pipefail
1414
cargo outdated --workspace
1515

1616
# Scan for unused dependencies
17-
cargo machete deep_causality deep_causality_algorithms deep_causality_discovery deep_causality_tensor deep_causality_rand deep_causality_num deep_causality_data_structures deep_causality_macros deep_causality_uncertain ultragraph
17+
cargo machete deep_causality deep_causality_algorithms deep_causality_discovery deep_causality_haft deep_causality_tensor deep_causality_rand deep_causality_num deep_causality_data_structures deep_causality_macros deep_causality_uncertain ultragraph
1818

1919
# Scan again to report all unfixed vulnerabilities
2020
# install or update with cargo install cargo-audit --locked

build/scripts/format.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ buildifier -r MODULE.bazel BUILD.bazel thirdparty/BUILD.bazel
1212
buildifier -r deep_causality/
1313
buildifier -r deep_causality_algorithms/
1414
buildifier -r deep_causality_data_structures/
15-
buildifier -r deep_causality_uncertain/
15+
buildifier -r deep_causality_discovery/
16+
buildifier -r deep_causality_haft/
1617
buildifier -r deep_causality_macros/
18+
buildifier -r deep_causality_num/
1719
buildifier -r deep_causality_rand/
20+
buildifier -r deep_causality_tensor/
21+
buildifier -r deep_causality_uncertain/
22+
buildifier -r examples/
1823
buildifier -r ultragraph/
1924

2025
# Code formatting

deep_causality_discovery/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ version = "0.2.0"
3333

3434
# External dependencies
3535
[dependencies]
36-
csv = {version = "1.3", default-features = false}
36+
csv = {version = "1.4", default-features = false}
3737
parquet = {version = "56", default-features = false}
3838

3939

deep_causality_haft/BUILD.bazel

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ rust_library(
77
]),
88
crate_root = "src/lib.rs",
99
tags = [
10-
"utils",
11-
"HKT",
1210
"HAFT",
11+
"HKT",
12+
"utils",
1313
],
1414
visibility = ["//visibility:public"],
1515
deps = [
16-
17-
],)
16+
],
17+
)
1818

1919
rust_doc(
2020
name = "doc",
@@ -32,6 +32,6 @@ rust_doc_test(
3232

3333
rust_test(
3434
name = "tests",
35-
crate = ":deep_causality_haft",
3635
srcs = glob(["tests/**"]),
36+
crate = ":deep_causality_haft",
3737
)

deep_causality_haft/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,13 @@ exclude = ["*.bazel", "*/*.bazel", "*.bazel.*", "BUILD", "BUILD.bazel", "MODULE
1717

1818
[dependencies]
1919

20+
21+
[[example]]
22+
name = "haft_simple_example"
23+
path = "examples/simple_haft.rs"
24+
25+
26+
[[example]]
27+
name = "haft_effect_system_example"
28+
path = "examples/effect_system_example.rs"
29+

deep_causality_haft/README.md

Lines changed: 134 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,27 @@
22

33
**HAFT: Higher-Order Abstract Functional Traits**
44

5-
`deep_causality_haft` is a sub-crate of the `deep_causality` project, providing traits for Higher-Kinded Types (HKTs) in Rust. This enables writing generic, abstract code that can operate over different container types like `Option<T>` and `Result<T, E>`.
5+
`deep_causality_haft` is a sub-crate of the `deep_causality` project, providing traits for Higher-Kinded Types (HKTs) in
6+
Rust. This enables writing generic, abstract code that can operate over different container types like `Option<T>` and
7+
`Result<T, E>`.
68

79
## What are Higher-Kinded Types?
810

9-
In Rust, types like `Option<T>` and `Vec<T>` are generic over a type `T`. We can think of `Option` and `Vec` as "type constructors": they take a type and produce a new type.
11+
In Rust, types like `Option<T>` and `Vec<T>` are generic over a type `T`. We can think of `Option` and `Vec` as "type
12+
constructors": they take a type and produce a new type.
1013

11-
A Higher-Kinded Type is an abstraction over these type constructors. It allows us to write functions that are generic not just over a type, but over the *shape* or *kind* of a type constructor. For example, we can write a function that works with any type constructor that can be mapped over (a `Functor`), without caring if it's an `Option`, a `Result`, or something else.
14+
A Higher-Kinded Type is an abstraction over these type constructors. It allows us to write functions that are generic
15+
not just over a type, but over the *shape* or *kind* of a type constructor. For example, we can write a function that
16+
works with any type constructor that can be mapped over (a `Functor`), without caring if it's an `Option`, a `Result`,
17+
or something else.
1218

13-
This crate provides the fundamental traits (`HKT`, `HKT2`, `HKT3`) and functional traits (`Functor`, `Monad`) to enable this pattern.
19+
This crate provides the fundamental traits (`HKT`, `HKT2`, `HKT3`, `HKT4`, `HKT5`) and functional traits (`Functor`,
20+
`Applicative`, `Monad`, `Foldable`) to enable this pattern.
1421

1522
## Usage
1623

17-
This crate uses a "witness" pattern to represent HKTs. For each type constructor (like `Option`), we define a zero-sized "witness" type (like `OptionWitness`) that implements the `HKT` trait.
24+
This crate uses a "witness" pattern to represent HKTs. For each type constructor (like `Option`), we define a
25+
zero-sized "witness" type (like `OptionWitness`) that implements the `HKT` trait.
1826

1927
### Example: Using `Functor` with `Option`
2028

@@ -49,7 +57,8 @@ fn main() {
4957

5058
### Example: Using `Functor` with `Result`
5159

52-
Here's how you can use the `Functor` trait with `Result<T, E>` via its witness type, `ResultWitness<E>`. `HKT2` is used here because `Result` has two generic parameters, and we are fixing the error type `E`.
60+
Here's how you can use the `Functor` trait with `Result<T, E>` via its witness type, `ResultWitness<E>`. `HKT2` is used
61+
here because `Result` has two generic parameters, and we are fixing the error type `E`.
5362

5463
```rust
5564
use deep_causality_haft::{Functor, HKT2, ResultWitness};
@@ -81,16 +90,128 @@ fn main() {
8190
}
8291
```
8392

84-
8593
## Type-Encoded Effect System
8694

87-
The `Effect3` and `MonadEffect3` traits provide a powerful mechanism for building a **type-encoded effect system**. This allows you to manage side-effects (like errors and logging) in a structured, safe, and composable way, which is particularly useful for building complex data processing pipelines.
95+
```rust
96+
use deep_causality_haft::utils_tests::*;
97+
use deep_causality_haft::{Effect5, MonadEffect5, HKT5};
98+
99+
// 1. Start with a pure value, lifting it into the effect context
100+
let initial_effect: MyEffectType<i32> = MyMonadEffect5::pure(10);
101+
102+
// 2. Define a collection of step functions
103+
// Each function takes an i32 and returns an effectful i32
104+
let step_functions: Vec<Box<dyn Fn(i32) -> MyEffectType<i32>>> = vec![
105+
Box::new(|x: i32| {
106+
MyCustomEffectType5 {
107+
value: x * 2,
108+
f1: None,
109+
f2: vec!["Operation A: Multiplied by 2".to_string()],
110+
f3: vec![1],
111+
f4: vec!["Trace: Executing step 1".to_string()],
112+
}
113+
}),
114+
Box::new(|x: i32| {
115+
MyCustomEffectType5 {
116+
value: x + 5,
117+
f1: None,
118+
f2: vec!["Operation B: Added 5".to_string()],
119+
f3: vec![1],
120+
f4: vec!["Trace: Executing step 2".to_string()],
121+
}
122+
}),
123+
Box::new(|x: i32| {
124+
MyCustomEffectType5 {
125+
value: x * 3,
126+
f1: None,
127+
f2: vec!["Operation C: Multiplied by 3".to_string()],
128+
f3: vec![1],
129+
f4: vec!["Trace: Executing step 3".to_string()],
130+
}
131+
}),
132+
];
133+
134+
// 3. Execute all step functions in sequence
135+
println!("Process Steps: ");
136+
let mut current_effect = initial_effect;
137+
for (i, f) in step_functions.into_iter().enumerate() {
138+
let prev_logs_len = current_effect.f2.len();
139+
current_effect = MyMonadEffect5::bind(current_effect, f);
140+
for log_msg in current_effect.f2.iter().skip(prev_logs_len) {
141+
println!(" Log (Step {}): {}", i + 1, log_msg);
142+
}
143+
}
144+
145+
println!("Sequenced outcome: {:?}", current_effect.value);
146+
```
147+
148+
When you run [the example ](/deep_causality_haft/examples/effect_system_example.rs)via:
149+
150+
`cargo run --example haft_effect_system_example`
151+
152+
You will see:
153+
154+
```text
155+
--- Type-Encoded Effect System Example (Arity 5) ---
156+
157+
Initial effect (pure 10): MyCustomEffectType5 { value: 10, f1: None, f2: [], f3: [], f4: [] }
158+
159+
Process Steps:
160+
Log (Step 1): Operation A: Multiplied by 2
161+
Log (Step 2): Operation B: Added 5
162+
Log (Step 3): Operation C: Multiplied by 3
163+
164+
Sequenced outcome: 75
165+
166+
... (Truncated)
167+
```
168+
169+
The `Effect3`, `Effect4`, `Effect5` and `MonadEffect3`, `MonadEffect4`, `MonadEffect5` traits provide a powerful
170+
mechanism for building a **type-encoded effect system**. This allows you to manage side-effects (like errors and
171+
logging) in a structured, safe, and composable way, which is particularly useful for building complex data processing
172+
pipelines.
173+
174+
The "Type-Encoded Effect System" in `deep_causality_haft` is a sophisticated pattern for managing side-effects (like
175+
errors, logging, or other contextual information) in a structured, safe, and composable manner within Rust. It leverages
176+
Rust's powerful type system to ensure that these effects are explicitly handled and tracked throughout your program.
177+
178+
Here's a breakdown of how it works:
179+
180+
1. **Effects as Types**: Instead of side-effects occurring implicitly, this system represents them explicitly as generic
181+
type parameters on a container type. For instance, you might have a custom effect type like
182+
`MyCustomEffectType<T, E, W>`, where:
183+
* `T` is the primary value of the computation.
184+
* `E` represents an error type.
185+
* `W` represents a warning or log type.
186+
By making these effects part of the type signature, the presence of potential side-effects becomes explicit and
187+
verifiable by the compiler.
188+
189+
2. **Higher-Kinded Type (HKT) Witnesses**: To make these effect types generic over their primary value `T` while keeping
190+
the effect types (`E`, `W`, etc.) fixed, the system utilizes Higher-Kinded Types (HKTs). Traits like `Effect3`,
191+
`Effect4`, and `Effect5` are used to "fix" a certain number of generic parameters of an underlying HKT type (e.g.,
192+
`HKT3`, `HKT4`, `HKT5`). This allows you to define a "witness" type (e.g., `MyEffectHktWitness<E, W>`) that
193+
represents the *shape* of your effect container with specific, fixed effect types, leaving one parameter (`T`) open
194+
for the actual value.
195+
196+
3. **Monadic Logic for Effects (`MonadEffect` traits)**: The core logic for how these effects are handled and combined
197+
is defined through `MonadEffect` traits (e.g., `MonadEffect3`, `MonadEffect4`, `MonadEffect5`). These traits provide:
198+
* **`pure`**: A method to lift a "pure" value (a value without any side-effects) into the effectful context.
199+
* **`bind`**: The central sequencing operation. It allows you to chain computations where each step might produce
200+
new effects. The implementation of `bind` dictates how effects from different steps are combined. For example, in
201+
the provided `MyCustomEffectType`, the `bind` implementation ensures that if an error occurs at any point, it
202+
propagates, and warnings from all steps are accumulated.
203+
204+
4. **Specialized Effect Handling (`LoggableEffect` traits)**: The system can be extended with specialized traits for
205+
specific types of effects. For example, `LoggableEffect3`, `LoggableEffect4`, and `LoggableEffect5` provide a `log`
206+
function. This function allows you to add a log message (of a specific fixed type, like `E::Fixed2` for
207+
`LoggableEffect3`) to the effect container without altering the primary value or causing an error.
208+
209+
5. **Compiler-Enforced Safety**: A significant advantage of this system is that because effects are part of the type
210+
signature, the Rust compiler statically verifies that all effects are handled correctly. This means that if a
211+
function is declared to produce a certain type of effect, the compiler ensures that the effect is either explicitly
212+
handled or propagated. This prevents common bugs related to unhandled errors or forgotten logging, leading to more
213+
robust and predictable code.
88214

89-
### How it Works
90215

91-
1. **Effects as Types**: Side-effects are represented by generic type parameters on a container (e.g., `E` for Error, `W` for Warning on a custom `MyEffect<T, E, W>` type).
92-
2. **Rules as Traits**: The logic for how to handle and combine these effects is defined by implementing the `MonadEffect3` trait. For example, the `bind` function can specify that the pipeline should halt on an error while accumulating warnings.
93-
3. **Compiler-Enforced Safety**: Because the effects are part of the type signature, the Rust compiler can statically verify that all effects are handled correctly. This prevents bugs and ensures that your pipeline code remains pure and focused on its core logic.
94-
4. **Extensibility**: This pattern is extensible. If you need to manage more side-effects, you can introduce `HKT4` and `Effect4` traits to handle them, without having to rewrite your core pipeline logic.
95216

96217

0 commit comments

Comments
 (0)