1pub use self::Order::*;
4use crate::term::Term::*;
5use crate::term::{Term, TermError};
6use std::{cmp, fmt, mem};
7
8#[derive(Debug, PartialEq, Eq, Clone, Copy)]
18pub enum Order {
19 NOR,
21 CBN,
23 HSP,
25 HNO,
27 APP,
29 CBV,
31 HAP,
34}
35
36pub fn beta(mut term: Term, order: Order, limit: usize) -> Term {
50 term.reduce(order, limit);
51 term
52}
53
54impl Term {
55 pub fn apply(&mut self, rhs: &Term) -> Result<(), TermError> {
73 self.unabs_ref()?;
74
75 self._apply(rhs, 0);
76
77 let ret = mem::replace(self, Var(0)); *self = ret.unabs().unwrap(); Ok(())
81 }
82
83 fn _apply(&mut self, rhs: &Term, depth: usize) {
84 match self {
85 Var(i) => match (*i).cmp(&depth) {
86 cmp::Ordering::Equal => {
87 rhs.clone_into(self); self.update_free_variables(depth - 1, 0); }
90 cmp::Ordering::Greater => {
91 *self = Var(*i - 1); }
93 _ => {}
94 },
95 Abs(ref mut abstracted) => abstracted._apply(rhs, depth + 1),
96 App(boxed) => {
97 let (ref mut lhs_lhs, ref mut lhs_rhs) = **boxed;
98 lhs_lhs._apply(rhs, depth);
99 lhs_rhs._apply(rhs, depth)
100 }
101 }
102 }
103
104 fn update_free_variables(&mut self, added_depth: usize, own_depth: usize) {
105 match self {
106 Var(ref mut i) => {
107 if *i > own_depth {
108 *i += added_depth
109 }
110 }
111 Abs(ref mut abstracted) => abstracted.update_free_variables(added_depth, own_depth + 1),
112 App(boxed) => {
113 let (ref mut lhs, ref mut rhs) = **boxed;
114 lhs.update_free_variables(added_depth, own_depth);
115 rhs.update_free_variables(added_depth, own_depth)
116 }
117 }
118 }
119
120 fn eval(&mut self, count: &mut usize) {
121 let to_apply = mem::replace(self, Var(0)); let (mut lhs, rhs) = to_apply.unapp().unwrap(); lhs.apply(&rhs).unwrap(); *self = lhs; *count += 1;
127 }
128
129 fn is_reducible(&self, limit: usize, count: usize) -> bool {
130 self.lhs_ref().and_then(|t| t.unabs_ref()).is_ok() && (limit == 0 || count < limit)
131 }
132
133 pub fn reduce(&mut self, order: Order, limit: usize) -> usize {
150 let mut count = 0;
151
152 match order {
153 CBN => self.beta_cbn(limit, &mut count),
154 NOR => self.beta_nor(limit, &mut count),
155 CBV => self.beta_cbv(limit, &mut count),
156 APP => self.beta_app(limit, &mut count),
157 HSP => self.beta_hsp(limit, &mut count),
158 HNO => self.beta_hno(limit, &mut count),
159 HAP => self.beta_hap(limit, &mut count),
160 }
161
162 count
163 }
164
165 fn beta_cbn(&mut self, limit: usize, count: &mut usize) {
166 if limit != 0 && *count == limit {
167 return;
168 }
169
170 if let App(_) = *self {
171 self.lhs_mut().unwrap().beta_cbn(limit, count);
172
173 if self.is_reducible(limit, *count) {
174 self.eval(count);
175 self.beta_cbn(limit, count);
176 }
177 }
178 }
179
180 fn beta_nor(&mut self, limit: usize, count: &mut usize) {
181 if limit != 0 && *count == limit {
182 return;
183 }
184
185 match *self {
186 Abs(ref mut abstracted) => abstracted.beta_nor(limit, count),
187 App(_) => {
188 self.lhs_mut().unwrap().beta_cbn(limit, count);
189
190 if self.is_reducible(limit, *count) {
191 self.eval(count);
192 self.beta_nor(limit, count);
193 } else {
194 self.lhs_mut().unwrap().beta_nor(limit, count);
195 self.rhs_mut().unwrap().beta_nor(limit, count);
196 }
197 }
198 _ => (),
199 }
200 }
201
202 fn beta_cbv(&mut self, limit: usize, count: &mut usize) {
203 if limit != 0 && *count == limit {
204 return;
205 }
206
207 if let App(_) = *self {
208 self.lhs_mut().unwrap().beta_cbv(limit, count);
209 self.rhs_mut().unwrap().beta_cbv(limit, count);
210
211 if self.is_reducible(limit, *count) {
212 self.eval(count);
213 self.beta_cbv(limit, count);
214 }
215 }
216 }
217
218 fn beta_app(&mut self, limit: usize, count: &mut usize) {
219 if limit != 0 && *count == limit {
220 return;
221 }
222
223 match *self {
224 Abs(ref mut abstracted) => abstracted.beta_app(limit, count),
225 App(_) => {
226 self.lhs_mut().unwrap().beta_app(limit, count);
227 self.rhs_mut().unwrap().beta_app(limit, count);
228
229 if self.is_reducible(limit, *count) {
230 self.eval(count);
231 self.beta_app(limit, count);
232 }
233 }
234 _ => (),
235 }
236 }
237
238 fn beta_hap(&mut self, limit: usize, count: &mut usize) {
239 if limit != 0 && *count == limit {
240 return;
241 }
242
243 match *self {
244 Abs(ref mut abstracted) => abstracted.beta_hap(limit, count),
245 App(_) => {
246 self.lhs_mut().unwrap().beta_cbv(limit, count);
247 self.rhs_mut().unwrap().beta_hap(limit, count);
248
249 if self.is_reducible(limit, *count) {
250 self.eval(count);
251 self.beta_hap(limit, count);
252 } else {
253 self.lhs_mut().unwrap().beta_hap(limit, count);
254 }
255 }
256 _ => (),
257 }
258 }
259
260 fn beta_hsp(&mut self, limit: usize, count: &mut usize) {
261 if limit != 0 && *count == limit {
262 return;
263 }
264
265 match *self {
266 Abs(ref mut abstracted) => abstracted.beta_hsp(limit, count),
267 App(_) => {
268 self.lhs_mut().unwrap().beta_hsp(limit, count);
269
270 if self.is_reducible(limit, *count) {
271 self.eval(count);
272 self.beta_hsp(limit, count)
273 }
274 }
275 _ => (),
276 }
277 }
278
279 fn beta_hno(&mut self, limit: usize, count: &mut usize) {
280 if limit != 0 && *count == limit {
281 return;
282 }
283
284 match *self {
285 Abs(ref mut abstracted) => abstracted.beta_hno(limit, count),
286 App(_) => {
287 self.lhs_mut().unwrap().beta_hsp(limit, count);
288
289 if self.is_reducible(limit, *count) {
290 self.eval(count);
291 self.beta_hno(limit, count)
292 } else {
293 self.lhs_mut().unwrap().beta_hno(limit, count);
294 self.rhs_mut().unwrap().beta_hno(limit, count);
295 }
296 }
297 _ => (),
298 }
299 }
300}
301
302impl fmt::Display for Order {
303 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
304 write!(
305 f,
306 "{}",
307 match *self {
308 NOR => "normal",
309 CBN => "call-by-name",
310 HSP => "head spine",
311 HNO => "hybrid normal",
312 APP => "applicative",
313 CBV => "call-by-value",
314 HAP => "hybrid applicative",
315 }
316 )
317 }
318}