1use serde::Serialize;
3
4use crate::{Error, Exp};
5
6#[derive(Serialize, Debug, Clone)]
7pub struct Var {
9 pub ident: String,
11 pub code: u32,
13 pub alpha_id: u32,
15}
16
17#[derive(Serialize, Debug, Clone)]
18pub struct Abs {
20 pub ident: String,
22 pub alpha_id: u32,
24 pub body: Box<JsExp>,
26 pub in_beta_redex: bool,
28 pub eta_redex: Option<u32>,
30}
31#[derive(Serialize, Debug, Clone)]
32pub struct App {
34 pub func: Box<JsExp>,
36 pub body: Box<JsExp>,
38 pub beta_redex: Option<u32>,
40}
41
42#[derive(Serialize, Debug, Clone)]
43pub enum InnerExp {
45 #[allow(missing_docs)]
46 Var(Var),
47 #[allow(missing_docs)]
48 Abs(Abs),
49 #[allow(missing_docs)]
50 App(App),
51}
52
53#[derive(Serialize, Debug, Clone)]
55pub struct JsExp {
56 pub parentheses: bool,
58 pub inner: InnerExp,
60}
61
62impl JsExp {
63 fn init_exp(exp: &crate::Exp<String>) -> Self {
64 match exp {
65 crate::Exp::Var(v) => Self {
66 parentheses: false,
67 inner: InnerExp::Var(Var {
68 ident: v.0.clone(),
69 code: v.1,
70 alpha_id: 0,
71 }),
72 },
73 crate::Exp::Abs(id, body) => Self {
74 parentheses: false,
75 inner: InnerExp::Abs(Abs {
76 ident: id.0.clone(),
77 alpha_id: 0,
78 body: Box::new(Self::init_exp(body)),
79 in_beta_redex: false,
80 eta_redex: None,
81 }),
82 },
83 crate::Exp::App(func, body) => Self {
84 parentheses: false,
85 inner: InnerExp::App(App {
86 func: Box::new(Self::init_exp(func)),
87 body: Box::new(Self::init_exp(body)),
88 beta_redex: None,
89 }),
90 },
91 }
92 }
93 fn for_each_captured_by<'a, F, D>(&'a mut self, de: u32, f: F, sum: Option<D>) -> Option<D>
94 where
95 F: Fn(&mut Var, Option<D>) -> Option<D> + Clone,
96 {
97 match &mut self.inner {
98 InnerExp::Var(var) => {
99 if var.code == de {
100 return f(var, sum);
101 }
102 return sum;
103 }
104 InnerExp::Abs(abs) => abs.body.for_each_captured_by(de + 1, f, sum),
105 InnerExp::App(app) => {
106 let sum = app.func.for_each_captured_by(de, f.clone(), sum);
107 app.body.for_each_captured_by(de, f, sum)
108 }
109 }
110 }
111 fn decorate(
113 &mut self,
114 is_app_func: bool,
115 is_app_body: bool,
116 is_tail: bool,
117 counter: &mut u32,
118 ) {
119 match &mut self.inner {
120 InnerExp::Var(var) => {
121 if var.alpha_id == 0 {
123 *counter += 1;
124 var.alpha_id = *counter
125 }
126 }
127 InnerExp::Abs(abs) => {
128 abs.in_beta_redex = is_app_func;
129 if is_app_func || !is_tail {
130 self.parentheses = true;
131 }
132 abs.body
133 .decorate(false, false, self.parentheses || is_tail, counter);
134 *counter += 1;
135 abs.alpha_id = *counter;
136 abs.body.for_each_captured_by(
137 1,
138 |v, _| {
139 v.alpha_id = *counter;
140 None
141 },
142 Some(()),
143 );
144 if let InnerExp::App(app) = &mut abs.body.inner {
145 if app
146 .func
147 .for_each_captured_by(1, |_, _| Some(()), None)
148 .is_none()
149 {
150 if let InnerExp::Var(var) = &app.body.inner {
151 if var.code == 1 {
152 *counter = *counter + 1;
153 abs.eta_redex = Some(*counter);
154 }
155 }
156 }
157 }
158 }
159 InnerExp::App(app) => {
160 if is_app_body {
161 self.parentheses = true;
162 }
163 app.func.decorate(true, false, false, counter);
164 app.body
165 .decorate(false, true, self.parentheses || is_tail, counter);
166 if let InnerExp::Abs(_) = app.func.inner {
167 *counter += 1;
168 app.beta_redex = Some(*counter)
170 }
171 }
172 }
173 }
174 pub(crate) fn from_exp(expr: &crate::Exp<String>) -> Self {
175 let mut exp = Self::init_exp(expr);
176 let mut counter = 0;
177 exp.decorate(false, false, true, &mut counter);
179 exp
180 }
181 fn into_app_ref(&self) -> Result<&App, Error> {
182 match &self.inner {
183 InnerExp::App(app) => Ok(app),
184 _ => Err(Error::InvalidInnerType),
185 }
186 }
187 fn into_abs_ref(&self) -> Result<&Abs, Error> {
188 match &self.inner {
189 InnerExp::Abs(abs) => Ok(abs),
190 _ => Err(Error::InvalidInnerType),
191 }
192 }
193 fn into_var(&self) -> Result<&Var, Error> {
194 match &self.inner {
195 InnerExp::Var(v) => Ok(v),
196 _ => Err(Error::InvalidInnerType),
197 }
198 }
199}
200
201impl Exp<String> {
202 pub(crate) fn beta_reduce_by_id(
209 &mut self,
210 display_exp: &JsExp,
211 id: u32,
212 ) -> Result<u32, Error> {
213 if let InnerExp::App(app) = &display_exp.inner {
214 if let Some(beta_redex) = app.beta_redex {
215 let alpha_id = app.func.into_abs_ref()?.alpha_id;
216 if beta_redex == id {
217 if self.beta_reduce() {
218 return Ok(alpha_id);
220 }
221 return Err(Error::InvalidRedex(id, self.to_string()));
222 }
223 }
224 }
225 match self {
226 Exp::Var(_) => Err(Error::RedexNotFound),
227 Exp::Abs(_, body) => body.beta_reduce_by_id(&display_exp.into_abs_ref()?.body, id),
228 Exp::App(func, body) => {
229 let app = display_exp.into_app_ref()?;
230 match func.beta_reduce_by_id(&app.func, id) {
231 Err(Error::RedexNotFound) => body.beta_reduce_by_id(&app.body, id),
232 r => r,
233 }
234 }
235 }
236 }
237 pub(crate) fn eta_reduce_by_id(
239 &mut self,
240 display_exp: &JsExp,
241 id: u32,
242 ) -> Result<u32, Error> {
243 if let Exp::Abs(_, _) = self {
244 let abs = display_exp.into_abs_ref()?;
245 if abs.eta_redex.is_some() && abs.eta_redex.unwrap() == id {
246 if self.eta_reduce() {
247 return Ok(abs.alpha_id);
248 }
249 return Err(Error::InvalidRedex(id, format!("{:?}", self)));
250 }
251 }
252 match self {
253 Exp::Var(_) => Err(Error::RedexNotFound),
254 Exp::Abs(_, body) => body.eta_reduce_by_id(&display_exp.into_abs_ref()?.body, id),
255 Exp::App(func, body) => {
256 let app = display_exp.into_app_ref()?;
257 match func.eta_reduce_by_id(&app.func, id) {
258 Err(Error::RedexNotFound) => body.eta_reduce_by_id(&app.body, id),
259 r => r,
260 }
261 }
262 }
263 }
264 pub(crate) fn find_var_by_alpha_id(
265 &mut self,
266 display_exp: &JsExp,
267 id: u32,
268 ) -> Option<&mut Self> {
269 match self {
270 Exp::Var(_) => {
271 if let Ok(var) = display_exp.into_var() {
272 if var.alpha_id == id {
273 return Some(self);
274 }
275 }
276 None
277 }
278 Exp::Abs(_, body) => {
279 let abs = display_exp.into_abs_ref().unwrap();
280 body.find_var_by_alpha_id(&abs.body, id)
281 }
282 Exp::App(func, body) => {
283 let app = display_exp.into_app_ref().unwrap();
284 match func.find_var_by_alpha_id(&app.func, id) {
285 None => body.find_var_by_alpha_id(&app.body, id),
286 r => r,
287 }
288 }
289 }
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use crate::lambda;
296
297 use super::{Abs, App, InnerExp, JsExp, Var};
298 impl JsExp {
299 fn into_var_mut(&mut self) -> &mut Var {
300 match &mut self.inner {
301 InnerExp::Var(var) => var,
302 _ => panic!("not var"),
303 }
304 }
305 fn into_app_mut(&mut self) -> &mut App {
306 match &mut self.inner {
307 InnerExp::App(app) => app,
308 _ => panic!("not app"),
309 }
310 }
311 fn into_abs_mut(&mut self) -> &mut Abs {
312 match &mut self.inner {
313 InnerExp::Abs(abs) => abs,
314 _ => panic!("not app"),
315 }
316 }
317 }
318
319 #[test]
320 fn test_jsexp() {
321 let exp = lambda!(x. x (x. x) (y. x (y. y) y));
322 let mut jsexp = JsExp::from_exp(&exp);
323 dbg!(&jsexp);
324 {
325 let id = jsexp.into_abs_mut().alpha_id;
326 assert_eq!(
327 id,
328 jsexp
329 .into_abs_mut()
330 .body
331 .into_app_mut()
332 .func
333 .into_app_mut()
334 .func
335 .into_var_mut()
336 .alpha_id
337 );
338 assert_eq!(
339 id,
340 jsexp
341 .into_abs_mut()
342 .body
343 .into_app_mut()
344 .body
345 .into_abs_mut()
346 .body
347 .into_app_mut()
348 .func
349 .into_app_mut()
350 .func
351 .into_var_mut()
352 .alpha_id
353 );
354 }
355 {
356 let abs = jsexp
357 .into_abs_mut()
358 .body
359 .into_app_mut()
360 .func
361 .into_app_mut()
362 .body
363 .into_abs_mut();
364 assert_eq!(abs.alpha_id, abs.body.into_var_mut().alpha_id);
365 }
366 }
367}