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_data
和 add_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 方法,允许引入新类型。
我没有把代码放在这里,这样可以直接在问题中进行参考,以及可能出现的编辑或新答案。
我正在尝试使用 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_data
和 add_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 方法,允许引入新类型。
我没有把代码放在这里,这样可以直接在问题中进行参考,以及可能出现的编辑或新答案。