提问人:안태찬 提问时间:10/31/2023 最后编辑:Chayim Friedman안태찬 更新时间:11/1/2023 访问量:69
Rust 智能指针问题
Rust smart pointer issue
问:
我正在尝试实现教会数字
//! representation of natural numbers using lambda calculus, named after
//! Alonzo Church. Each Church numeral corresponds to a natural number `n`
//! and is represented as a higher-order function that applies a given function `f` `n` times.
//! ex) f(f(f(x))) is equal to number 3
use std::rc::Rc;
/// Church numerals are represented as higher-order functions that take a function `f`
pub type Church<T> = Rc<dyn Fn(Rc<dyn Fn(T) -> T>) -> Rc<dyn Fn(T) -> T>>;
/// Implement a function to convert a Church numeral to a usize type.
pub fn to_usize<T: 'static + Default>(n: Church<T>) -> usize {
use std::cell::RefCell;
let counter = Rc::new(RefCell::new(0));
let counter_clone = Rc::clone(&counter);
let result_func = n(Rc::new(move |x| {
*counter_clone.borrow_mut() += 1;
x
}));
let _ = result_func(Default::default());
// Extract the value from the reference-counted cell
let result = *counter.borrow();
result
}
我正在尝试实现to_usize函数,它将给定的 Church 转换为其相应的值。
但是,计数器值不会更新,仍保持零。我认为 counter 和 counter_clone 有相同的参考......
答:
0赞
Aurel Bílý
11/1/2023
#1
我看不出代码的行为有问题:使用正确的输入(教会数字),它会产生预期的数字。
println!("0: {}", to_usize(Rc::new(|f: Rc<dyn Fn(usize) -> usize>| Rc::new(move |x| x))));
println!("1: {}", to_usize(Rc::new(|f: Rc<dyn Fn(usize) -> usize>| Rc::new(move |x| f(x)))));
println!("2: {}", to_usize(Rc::new(|f: Rc<dyn Fn(usize) -> usize>| Rc::new(move |x| f(f(x)))))));
println!("3: {}", to_usize(Rc::new(|f: Rc<dyn Fn(usize) -> usize>| Rc::new(move |x| f(f(f(x)))))));
按预期输出。也许您作为输入传递的函数不正确?0
3
另外,type 参数 of 不能准确地捕获您希望从 Church 数字中获得的内容,即它接收的函数在其输入中是多态的。相反,类型参数受调用站点的约束并在调用站点上选择,即使调用站点不使用它也是如此。因此,您跟踪“发生了多少次呼叫”的方式正在使用(正如@Chayim在评论中指出的那样,这可能是 ),这是令人惊讶的。to_usize
to_usize
RefCell
Cell
理想情况下,可以选择使用类型参数实例化 Church 数字,但这需要 Rust 不提供的 2 级多态性 ()。to_usize
usize
for <T> Rc<dyn Fn(T) -> T>
作为折衷方案,使用额外的特征约束:
pub fn to_usize<
T: 'static + Default + std::ops::Add<usize, Output = T>
>(n: Church<T>) -> T {
n(Rc::new(|x| x + 1))(Default::default())
}
评论
to_usize()
Cell
而不是 .RefCell