Rust 中多个泛型转换的 GADT

GADTs for multiple generics transformations in Rust

我正在尝试使用 Rust 中的递归泛型枚举设计一个执行图。我想制作一个 eval 函数,它递归地计算预定义的 map 闭包,但是每个 map 函数都可以更改枚举类型,因此由于类型不同,我得到了一个编译错误。这是我的代码:

use std::rc::Rc;

enum ExecutionGraph<T, H, F = fn(T) -> H> {
    Cons(Vec<T>),
    Map(F, Rc<ExecutionGraph<T, H>>),
}

// Impl for add a Cons "node" or a Map "node"
impl<T, H> ExecutionGraph<T, H, fn(T) -> H> {
    fn new_data(data: Vec<T>) -> Self {
        ExecutionGraph::Cons(data)
    }

    fn add_map(a_function: fn(T) -> H, execution_graph: ExecutionGraph<T, H, fn(T) -> H>) -> Self {
        ExecutionGraph::Map(a_function, Rc::new(execution_graph))
    }
}

// Complete evaluation of the execution graph
fn eval<T, H>(execution_graph: &ExecutionGraph<T, H, fn(T) -> H>) -> Vec<T>
where
    T: std::clone::Clone,
    std::vec::Vec<T>: std::iter::FromIterator<H>,
{
    match execution_graph {
        ExecutionGraph::Cons(data) => data.to_vec(),
        ExecutionGraph::Map(closure, e1) => eval(&(*e1)).into_iter().map(closure).collect(),
    }
}

fn main() {
    let execution_graph = ExecutionGraph::new_data(vec![1, 2, 3]);

    // let map_function: fn(u32) -> u32 = |x: u32| x * 8; // This work!
    let map_function: fn(u32) -> bool = |x: u32| x % 2 == 0; // This doesn't
    let execution_graph_2 = ExecutionGraph::add_map(map_function, execution_graph);
    let execution_result = eval(&execution_graph_2);

    println!("Result of execution = {:#?}", execution_result);
}

add_dataadd_map 函数按预期工作。但是当我调用 eval 函数时,出现以下错误:

   |     let execution_result = eval(&execution_graph_2);
   |                                 ^^^^^^^^^^^^^^^^^^ expected u32, found bool
   |
   = note: expected type `&ExecutionGraph<_, _>`
              found type `&ExecutionGraph<u32, bool>`>`

为什么会出现此错误? 我定义了一个通用参数和一个可以更改结果类型的通用函数。 如何允许数据中所有可能的转换?将来,会有更多的函数有同样的问题,比如笛卡尔积return是一个元组。请注意,如果闭包具有与输入相同的 return 类型,则没有问题。如果有人能帮我解决这个问题,我将不胜感激。

正如用户在 Rust 的 my question in the official forum 中提到的那样。该语言不支持广义代数数据类型 (GADT),后者是解决此类问题的正确工具。

作为替代方案,我们没有提出类型属于 ENUM 的方案,使其不太灵活,而是提出了 class 方法,允许引入新类型。

我没有把代码放在这里,这样可以直接在问题中进行参考,以及可能出现的编辑或新答案。