Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 非类型化lambda演算能否仅使用泛型实现?_Generics_Rust_Traits_Lambda Calculus - Fatal编程技术网

Generics 非类型化lambda演算能否仅使用泛型实现?

Generics 非类型化lambda演算能否仅使用泛型实现?,generics,rust,traits,lambda-calculus,Generics,Rust,Traits,Lambda Calculus,考虑以下非类型lambda演算的实现: pub enum Term { Var(usize), // a variable with a De Bruijn index Abs(Box<Term>), // an abstraction App(Box<Term>, Box<Term>) // an application } impl Term { ... } pub枚举术语{ Var(usize),//一个带有De Br

考虑以下非类型lambda演算的实现:

pub enum Term {
    Var(usize), // a variable with a De Bruijn index
    Abs(Box<Term>), // an abstraction
    App(Box<Term>, Box<Term>) // an application
}

impl Term {
    ...
}
pub枚举术语{
Var(usize),//一个带有De Bruijn索引的变量
Abs(Box),//抽象
App(Box,Box)//应用程序
}
内隐术语{
...
}
我觉得这个设计虽然简单、简洁,但可以从转化为特性中获益。不同的术语应该有不同的方法集,例如,只有抽象应该是“不可抽象的”,只有应用程序应该是可评估的

我知道Enum vs.traits中的常见论点;即使Enum是这里更好的选择,我还是想知道它是否可行

到目前为止,我的基本构建块大致如下:

#[derive(Clone, PartialEq, Eq)]
pub struct Var(usize);

#[derive(Clone, PartialEq, Eq)]
pub struct Abs<T: Term>(T);

#[derive(Clone, PartialEq, Eq)]
pub struct App<T: Term, U: Term>(T, U);

pub trait Term: Clone {
    fn abs(self) -> Abs<Self> { Abs(self) }

    fn app<T: Term>(self, other: T) -> App<Self, T> { App(self, other) }

    fn update_free_variables(&mut self, added_depth: usize, own_depth: usize);

    fn _apply<T: Term>(&mut self, other: &mut T, depth: usize); // this is a helper function that enables term tree traversal for Abs<T>::apply

    fn is_reducible(&self, limit: usize, count: &usize) -> bool;

    fn beta_reduce(&mut self, order: Order, limit: usize, verbose: bool) -> usize;
}

impl Var {
    pub fn new(index: usize) -> Self {
        assert!(index > 0);
        Var(index)
    }
}

impl<T: Term> Abs<T> {
    fn unabs(self) -> T {
        self.0
    }

    fn apply<U: Term>(mut self, other: &mut U) -> T {
        self._apply(other, 0);
        self.unabs()
    }
}

impl<T: Term, U: Term> App<T, U> {
    fn unapp(self) -> (T, U) {
        (self.0, self.1)
    }
}

// and some impl Term for X
#[派生(克隆、部分、相等)]
发布结构变量(usize);
#[派生(克隆、部分q、Eq)]
pub结构Abs(T);
#[派生(克隆、部分q、Eq)]
发布结构应用程序(T,U);
术语:克隆{
fn abs(self)->abs{abs(self)}
fn app(self,other:T)->app{app(self,other)}
fn更新自由变量(&mut self,添加深度:usize,拥有深度:usize);
fn _apply(&mut-self,other:&mut-T,depth:usize);//这是一个帮助函数,用于为Abs::apply启用术语树遍历
fn是可约的(&self,limit:usize,count:&usize)->bool;
fn beta_reduce(&mut self,order:order,limit:usize,verbose:bool)->usize;
}
impl-Var{
新发布(索引:usize)->Self{
断言!(索引>0);
风险值(指数)
}
}
嵌入式Abs{
fn unabs(自身)->T{
self.0
}
fn应用(多个自身,其他:&mut U)->T{
自身应用(其他,0);
self.unabs()
}
}
impl应用程序{
fn UNPC(自身)->(T,U){
(self.0,self.1)
}
}
//还有一些X的简单术语
虽然实现基本功能非常容易,但在一些地方我很难找到正确的解决方案。我需要能够做到以下几点:

  • 创建一个解析器,它可以用一个函数解释任何术语,从普通变量到复杂术语
  • 用另一个变量或不同的术语替换任何变量(无论嵌套有多深)
  • 递归地减少术语(我不确定解析的术语是否可能是trait对象)
我更愿意尝试自己实现它,我只是需要一些关于方向的建议。甚至没有枚举包装器也可以吗?如果是,我应该采取什么方法(在对象安全方面,
不安全
欺骗等)?

枚举与特征 不同的术语应该有不同的方法集,例如,只有抽象应该是“不可抽象的”,只有应用程序应该是可评估的

我不认为这是基于特质的设计的一个好论点。通过模式匹配,枚举在运行时公开术语类型之间的差异,但特征隐藏了这些差异,迫使您以相同的方式对待所有术语。您可能在编译时不知道术语的类型,因此为不同类型的术语指定不同的方法没有多大意义。如果您希望使用特定于每种类型的术语的功能,而不是通过统一接口单独与术语进行多态交互,那么您应该使用基于枚举的设计

如果您决定坚持使用基于特征的实现,那么您将需要删除所有通用方法,并使用特征对象。如果动态分派具有泛型方法,则无法将其与
术语一起使用,因为它不是对象安全的

基于特征的设计的一个潜在优势是可扩展性,但在这种情况下,这不是一个问题,因为非类型lambda演算的定义是固定的

三个问题 创建一个解析器,它可以用一个函数解释任何术语,从普通变量到复杂术语

如果所有应用程序都需要用括号括起来,那么解析表达式应该相当简单。我在解析方面没有太多经验,但我可能会尝试以下递归方法:

fn substitute(&mut self, variable_number: usize, other: &Term);
读取一个术语,给定变量堆栈的可变引用(以空开头):
如果下一个字符是左括号:
消费它。
读一个术语。
读一个术语。
确保下一个字符是右括号,并使用它。
返回两个术语的应用程序。
如果下一个字符是lambda:
消费它。
确保下一个字符是变量,然后使用它。
确保下一个字符是一个点,并使用它。
将变量推送到变量堆栈中。
读一个术语。
将变量从堆栈中弹出。
返回术语的抽象。
如果下一个字符是变量:
消费它。
搜索变量堆栈,从顶部查找变量的第一个索引。
返回带有此索引的变量项。
您可以对其进行修改,以接受lambda演算表示法中的常见快捷方式,例如
((ab)c)
。目前,它将接受
λx.λy.λz.((x z)(y z))
,但不接受
λx.λy.λz.x z(y z)

用另一个变量或不同的术语替换任何变量(无论嵌套有多深)

我假设变量项存储的数字是变量引入点和使用点之间的抽象层数量。如果是这种情况,那么您可以递归地遍历结构,同时记住当前的抽象深度。当遇到与该数字匹配的变量时,该变量将替换为给定的项,但该项中的所有自由变量(可通过查找数字大于其在给定项中的抽象深度的变量找到)应为