Skip to content

Commit 4a385f9

Browse files
committed
Trying a new approach with HKT-like traits with type bounds.
Signed-off-by: Marvin Hansen <[email protected]>
1 parent dac5be3 commit 4a385f9

File tree

7 files changed

+127
-9
lines changed

7 files changed

+127
-9
lines changed

deep_causality_uncertain/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub use crate::alias::{MaybeUncertainBool, MaybeUncertainF64, UncertainBool, Unc
1919
// Errors
2020
pub use crate::errors::UncertainError;
2121
// Traits
22+
pub use crate::traits::hkt::{UncertainApplicative, UncertainFunctor, UncertainMonad};
23+
pub use crate::traits::probabilistic_type::ProbabilisticType;
2224
pub use crate::traits::sampler::Sampler;
2325
// Types
2426
pub use crate::types::cache::{GlobalSampleCache, SampledValue, with_global_cache};
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
6+
use crate::ProbabilisticType;
7+
use deep_causality_haft::HKT;
8+
9+
pub trait UncertainFunctor<F: HKT> {
10+
fn fmap<A, B, Func>(m_a: F::Type<A>, f: Func) -> F::Type<B>
11+
where
12+
Func: FnMut(A) -> B,
13+
A: ProbabilisticType,
14+
B: ProbabilisticType;
15+
}
16+
17+
pub trait UncertainApplicative<F: HKT> {
18+
fn pure<T>(value: T) -> F::Type<T>
19+
where
20+
T: ProbabilisticType;
21+
22+
fn apply<A, B, Func>(f_ab: F::Type<Func>, f_a: F::Type<A>) -> F::Type<B>
23+
where
24+
Func: FnMut(A) -> B,
25+
A: ProbabilisticType,
26+
B: ProbabilisticType;
27+
}
28+
29+
pub trait UncertainMonad<F: HKT> {
30+
fn bind<A, B, Func>(m_a: F::Type<A>, f: Func) -> F::Type<B>
31+
where
32+
Func: FnMut(A) -> F::Type<B>,
33+
A: ProbabilisticType,
34+
B: ProbabilisticType;
35+
}

deep_causality_uncertain/src/traits/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
* SPDX-License-Identifier: MIT
33
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
44
*/
5+
pub(crate) mod hkt;
6+
pub(crate) mod probabilistic_type;
57
pub mod sampler;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
6+
use crate::ProbabilisticType;
7+
use crate::errors::UncertainError;
8+
use crate::types::cache::SampledValue;
9+
10+
impl ProbabilisticType for bool {
11+
fn to_sampled_value(&self) -> SampledValue {
12+
SampledValue::Bool(*self)
13+
}
14+
15+
fn from_sampled_value(value: SampledValue) -> Result<Self, UncertainError> {
16+
match value {
17+
SampledValue::Bool(b) => Ok(b),
18+
_ => Err(UncertainError::UnsupportedTypeError(
19+
"Expected bool SampledValue".to_string(),
20+
)),
21+
}
22+
}
23+
24+
fn default_value() -> Self {
25+
false
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
* Copyright (c) "2025" . The DeepCausality Authors and Contributors. All Rights Reserved.
4+
*/
5+
6+
use crate::ProbabilisticType;
7+
use crate::errors::UncertainError;
8+
use crate::types::cache::SampledValue;
9+
10+
impl ProbabilisticType for f64 {
11+
fn to_sampled_value(&self) -> SampledValue {
12+
SampledValue::Float(*self)
13+
}
14+
15+
fn from_sampled_value(value: SampledValue) -> Result<Self, UncertainError> {
16+
match value {
17+
SampledValue::Float(f) => Ok(f),
18+
_ => Err(UncertainError::UnsupportedTypeError(
19+
"Expected f64 SampledValue".to_string(),
20+
)),
21+
}
22+
}
23+
24+
fn default_value() -> Self {
25+
0.0
26+
}
27+
}
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+
mod bool_probabilistic_type;
6+
mod f64_probabilistic_type;
7+
8+
use crate::errors::UncertainError;
9+
use crate::types::cache::SampledValue;
10+
11+
pub trait ProbabilisticType {
12+
/// Converts the type into an internal `SampledValue` representation.
13+
fn to_sampled_value(&self) -> SampledValue;
14+
/// Attempts to convert an internal `SampledValue` back into this type.
15+
fn from_sampled_value(value: SampledValue) -> Result<Self, UncertainError>
16+
where
17+
Self: Sized;
18+
/// Provides a default or zero-equivalent value for the type.
19+
fn default_value() -> Self;
20+
}

specs/008-hkt-uncertain-specs/plan.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,26 @@ The original internal representation of `Uncertain<T>` relies on an `Arc<Computa
5252
- **Generic Containment**: `ConstTree` can generically hold the probabilistic values of `Uncertain<T>`, facilitating `A -> B` type transformations.
5353
- **Structured Composition**: The tree structure offers a clear and recursive mechanism for implementing `pure`, `apply`, and `bind` operations, enabling the composition and sequencing of uncertain computations.
5454

55-
However, a critical obstacle remains: the `Functor`, `Applicative`, and `Monad` traits from `deep_causality_haft` define operations with generic type parameters `A` and `B` (e.g., `Func: FnMut(A) -> B`). For `Uncertain<T>`, where `T` represents a probability distribution, the types `A` and `B` cannot be arbitrary. Currently, `deep_causality_uncertain` primarily supports distributions over `f64` and `bool` (via `SampledValue`). Therefore, even with `ConstTree`, the HKT implementations will be inherently constrained: `A` and `B` must be types for which `Uncertain<T>` can meaningfully define and transform probability distributions. This means implementations will require specific trait bounds (e.g., `A: Into<SampledValue>`, `B: From<SampledValue>`) to ensure type compatibility with the underlying stochastic model, limiting the full generality implied by the `Haft` trait signatures.
55+
However, a critical obstacle remains: the `Functor`, `Applicative`, and `Monad` traits from `deep_causality_haft` define operations with generic type parameters `A` and `B` (e.g., `Func: FnMut(A) -> B`). For `Uncertain<T>`, where `T` represents a probability distribution, the types `A` and `B` cannot be arbitrary. They must be types for which `Uncertain<T>` can meaningfully define and transform probability distributions (i.e., `ProbabilisticType`). This inherent constraint conflicts with the unconstrained generic parameters of the `deep_causality_haft` HKT traits.
56+
57+
To resolve this, `Uncertain<T>` will *not* directly implement the `deep_causality_haft` HKT traits. Instead, a set of *independent HKT-like traits* (`UncertainFunctor`, `UncertainApplicative`, `UncertainMonad`) will be defined. These independent traits will mirror the method signatures of their `deep_causality_haft` counterparts but will explicitly include the `ProbabilisticType` bounds on their generic type parameters (`A` and `B`). This allows `Uncertain<T>` to provide monadic functionality with the necessary type constraints, while still adhering to the HKT pattern.
5658

5759
**Practical Solution for Monadic `Uncertain` and `MaybeUncertain`:**
5860
To bridge this gap and enable robust HKT implementations, the following architectural changes are proposed:
5961
1. **Introduce `ProbabilisticType` Trait**: A new trait `ProbabilisticType` will be defined in `deep_causality_uncertain/src/traits/probabilistic_type.rs`. This trait will be implemented by types that `Uncertain<T>` can meaningfully operate on (initially `f64` and `bool`), providing methods for conversion to/from `SampledValue` and a `default_value`.
6062
2. **Constrain `Uncertain<T>`**: The `Uncertain<T>` struct will be constrained with `T: ProbabilisticType`, ensuring type compatibility throughout its operations.
61-
3. **Redesign `ConstTree` Node Content**: The `ConstTree` will no longer directly hold `T`. Instead, it will hold an enum, `UncertainNodeContent<T: ProbabilisticType>`, which can represent:
62-
* `Value(T)` (for leaf nodes/point distributions).
63-
* `Distribution(DistributionEnum<T>)` (for probabilistic leaf nodes).
64-
* `FunctionOp { func: Arc<dyn Fn(T) -> T + Send + Sync>, operand: Box<ConstTree<UncertainNodeContent<T>>> }` (for `fmap`-like operations).
65-
* `MonadicFunctionOp { func: Arc<dyn Fn(T) -> Uncertain<T> + Send + Sync>, operand: Box<ConstTree<UncertainNodeContent<T>>> }` (for `bind`-like operations).
66-
* Other symbolic operations (arithmetic, logical, conditional) generic over `T: ProbabilisticType`).
67-
The `root_node` in `Uncertain<T>` will become `Arc<ConstTree<UncertainNodeContent<T>>>`.
63+
3. **Redesign `ComputationNode` to `UncertainNodeContent` using `ConstTree`**: The existing `ComputationNode` enum will be **deleted and replaced**. The new internal representation for `Uncertain<T>`'s computation graph will be `ConstTree<UncertainNodeContent<T>>`.
64+
* `UncertainNodeContent<T>` will be a new enum (generic over `T: ProbabilisticType`) that represents the nodes in the computation graph. It will contain variants for:
65+
* `Value(SampledValue)` (for leaf nodes/point distributions).
66+
* `Distribution(DistributionEnum<T>)` (for probabilistic leaf nodes).
67+
* `PureOp { value: SampledValue }` (for `pure` operations).
68+
* `FmapOp { func: Arc<dyn SampledFmapFn>, operand: ConstTree<UncertainNodeContent<T>> }` (for `fmap`-like operations).
69+
* `ApplyOp { func: Arc<dyn SampledFmapFn>, arg: ConstTree<UncertainNodeContent<T>> }` (for `apply`-like operations).
70+
* `BindOp { func: Arc<dyn SampledBindFn>, operand: ConstTree<UncertainNodeContent<T>> }` (for `bind`-like operations).
71+
* Other symbolic operations (arithmetic, logical, conditional) will be adapted to use `SampledValue` and `ConstTree` operands.
72+
* `SampledFmapFn` and `SampledBindFn` traits (operating on `SampledValue`) will be defined to handle type erasure for closures. * The `root_node` in `Uncertain<T>` will become `ConstTree<UncertainNodeContent<T>>`.
6873
4. **Rewrite Core Logic**: All `Uncertain<T>` constructors, operator overloads, and the `SequentialSampler`'s `evaluate_node` will be rewritten to build, traverse, and interpret this new `ConstTree<UncertainNodeContent<T>>` structure, leveraging `ProbabilisticType` for type conversions during sampling.
69-
5. **Implement Haft Traits**: The `Functor`, `Applicative`, and `Monad` traits for `UncertainWitness` and `MaybeUncertainWitness` will be implemented by symbolically embedding the generic `Func` parameters within the `ConstTree`'s `UncertainNodeContent` and ensuring `A` and `B` adhere to `ProbabilisticType`.
74+
5. **Implement HKT-like Traits**: `UncertainWitness` and `MaybeUncertainWitness` will **not** directly implement `deep_causality_haft`'s `Functor`, `Applicative`, and `Monad` traits. Instead, they will implement *independent HKT-like traits* (`UncertainFunctor`, `UncertainApplicative`, `UncertainMonad`) that mirror the `deep_causality_haft` signatures but explicitly include `ProbabilisticType` bounds on their methods. If `deep_causality_haft`'s traits are ever needed for `UncertainWitness` (e.g., for generic functions that expect *any* `Functor`), they would be implemented by **dispatching** to these independent traits, potentially with additional `where` clauses to ensure `A` and `B` adhere to `ProbabilisticType`.
7075

7176
This comprehensive approach allows `Uncertain<T>` and `MaybeUncertain<T>` to become fully monadic by representing their computations as a symbolic `ConstTree` and explicitly managing type compatibility through `ProbabilisticType`, thus enabling their use as monadic subtypes within `Propagating Effect`.
7277

0 commit comments

Comments
 (0)