2016-01-10 74 views
0

我想實現一個非常基本的lambda減速器。出現的第一個問題是用什麼樣的數據類型來實現AST? In Haskell this would be an ADT。生鏽,這似乎是正確的方法是使用一個枚舉和Box ES:在Rust中遍歷「ADT」的正確方法是什麼?

enum Term{ 
    Num(i64), 
    Plus(Box<Term>, Box<Term>), 
    Var(i64), 
    Lam(i64, Box<Term>), 
    App(Box<Term>, Box<Term>) 
} 

這似乎是一個不錯的選擇,但由於我在拉斯特對於新手,它很可能是這個問題我有 - - 這就是 - 我只是選擇了錯誤的數據類型,如果我選擇了正確的數據類型表示,我的問題就會消失。如果發生這種情況,請讓我知道!

現在到了一步減少。繼Haskell代碼參考,我們最終是這樣的:

fn reduceOneStep(t: Term) -> (Term, bool) { 
    match t { 
     Term::Num(a) => (t, false), 
     Term::Plus(t1, t2) => 
     match (*t1, *t2) { 
      (Term::Num(a), Term::Num(b)) => (Term::Num(a + b), true), 
      (Term::Num(a), w) => 
      match reduceOneStep(w) { 
       (t, b) => if b { (Term::Plus(t1, Box::new(t)), true) } else { (Term::Plus(t1, t2), false) } 
      }, 
      _ => (Term::Num(1), false) //ignore .. this is just to satisfy typing and totality 
     }, 
     x => (Term::Num(1), false) //ignore .. this is just to satisfy typing and totality 
    } 
} 

然而,行

(t, b) => if b { (Term::Plus(t1, Box::new(t)), true) } else { (Term::Plus(t1, t2), false) } 

失敗編譯。原因是我「使用移動的值t1」 我不太瞭解這個錯誤,也不知道如何解決它。我嘗試了一些其他變體,但他們沒有解決問題。我的問題是:我做錯了什麼?

+3

是的,枚舉是Rust實現ADT的方式。 –

+0

@Shepmaster:對不起,我很困惑。我的第一個「問題」並不是真正的問題。這是修辭,我的解釋是我試圖反映一段Haskell代碼。但是,我是這種語言的新手,所以如果有人對我的數據類型有什麼建議,我很樂意聽到這個消息,這似乎是合理的。我改變了這個問題來反映這一點。 –

回答

1

(附註:這會,如果你使用的Result類型,而不是與裏面的一個boolean元組可能會更好,我會跟你寫的這個答案雖然方式堅持下去。)

錯誤消息表示您不能使用移動的值t1t2,因爲這些值在您取消引用並在它們上進行匹配時已移動。

已存儲在t1和變量awt2現已擁有的信息,並且在比賽中表現的一個分支,t,所以你必須使用這些。如果我錯了,請糾正我。

所以,你可以去實現讓你的例子,如果,工作行內:

(t, b) => if b { (Term::Plus(t1, Box::new(t)), true) } else { (Term::Plus(t1, t2), false) } 

您與Box::new(w)替換t1Box::new(Term::Num(a)),和t2。也就是說,有一些的縮進,就是:

(t, b) => if b { 
    (Term::Plus(Box::new(Term::Num(a)), Box::new(t)), true) 
} else { 
    (Term::Plus(Box::new(Term::Num(a)), Box::new(w)), false) 
} 

這也失敗,但因爲通話reduceOneStep(w)注意到w所有權。這可以是固定的通過使reduceOneStep借用它的參數,而不是:

fn reduceOneStep(t: &Term) -> (Term, bool) { 
    match t { 
    &Term::Num(a) => (*t, false), 
    &Term::Plus(t1, t2) => 
    match (*t1, *t2) { 
     (Term::Num(a), Term::Num(b)) => (Term::Num(a + b), true), 
     (Term::Num(a), w) => 
     match reduceOneStep(&w) { 
     (t, b) => if b { 
      (Term::Plus(Box::new(Term::Num(a)), Box::new(t)), true) 
     } else { 
      (Term::Plus(Box::new(Term::Num(a)), Box::new(w)), false) 
     } 
     }, 
     _ => (Term::Num(1), false) //ignore .. this is just to satisfy typing and totality 
    }, 
    x => (Term::Num(1), false) //ignore .. this is just to satisfy typing and totality 
    } 
} 

但是,這裏有更多的錯誤,他說cannot move out of borrowed content,指着它返回*t。這是因爲它既不能將借款歸還給所有者,又要歸還其中的一部分,因爲可以釋放一部分,而另一部分可以留下。解決這個問題的方法之一是#[derive(Clone)]Term枚舉,並使用:

fn reduceOneStep(t: &Term) -> (Term, bool) { 
    match t { 
    &Term::Num(a) => (t.clone(), false), 
    &Term::Plus(t1, t2) => 
    match (*t1, *t2) { 
     (Term::Num(a), Term::Num(b)) => (Term::Num(a + b), true), 
     (Term::Num(a), w) => 
     match reduceOneStep(&w) { 
     (t, b) => if b { 
      (Term::Plus(Box::new(Term::Num(a)), Box::new(t)), true) 
     } else { 
      (Term::Plus(Box::new(Term::Num(a)), Box::new(w.clone())), false) 
     } 
     }, 
     _ => (Term::Num(1), false) //ignore .. this is just to satisfy typing and totality 
    }, 
    x => (Term::Num(1), false) //ignore .. this is just to satisfy typing and totality 
    } 
} 

但是,這仍然具有相同的錯誤。呵呵。錯誤消息在它下面有這個提示:help: to prevent the move, use `ref t1` or `ref mut t1` to capture value by reference。然後固定的一些類型不匹配,並與框擺弄derefs借用和之後,我終於得到這個工作:

fn reduceOneStep(t: &Term) -> (Term, bool) { 
    match t { 
    &Term::Num(a) => (t.clone(), false), 
    &Term::Plus(ref t1, ref t2) => 
    match (&**t1, &**t2) { 
     (&Term::Num(a), &Term::Num(b)) => (Term::Num(a + b), true), 
     (&Term::Num(a), w) => 
     match reduceOneStep(&w) { 
     (t, b) => if b { 
      (Term::Plus(Box::new(Term::Num(a)), Box::new(t)), true) 
     } else { 
      (Term::Plus(Box::new(Term::Num(a)), Box::new(w.clone())), false) 
     } 
     }, 
     _ => (Term::Num(1), false) //ignore .. this is just to satisfy typing and totality 
    }, 
    x => (Term::Num(1), false) //ignore .. this is just to satisfy typing and totality 
    } 
} 

我和防鏽一個初學者,現在,如果有人能幫助我理解爲什麼這個工程,我我會非常感激。

相關問題