scheme_rs/
num.rs

1use crate::{
2    continuation::Continuation,
3    error::RuntimeError,
4    gc::{Gc, Trace},
5    value::Value,
6};
7use num::{complex::Complex64, FromPrimitive, ToPrimitive, Zero};
8use scheme_rs_macros::builtin;
9use rug::{Complete, Integer, Rational};
10use std::{
11    cmp::Ordering,
12    fmt,
13    ops::{Add, Div, Mul, Neg, Sub},
14    sync::Arc,
15};
16
17#[derive(Debug, Clone)]
18pub enum Number {
19    FixedInteger(i64),
20    BigInteger(Integer),
21    Rational(Rational),
22    Real(f64),
23    Complex(Complex64),
24}
25
26impl Number {
27    fn is_zero(&self) -> bool {
28        match self {
29            Self::FixedInteger(i) => i.is_zero(),
30            Self::BigInteger(i) => i.is_zero(),
31            Self::Rational(r) => r.is_zero(),
32            Self::Real(r) => r.is_zero(),
33            Self::Complex(c) => c.is_zero(),
34        }
35    }
36
37    fn is_even(&self) -> bool {
38        use num::Integer;
39        match self {
40            Self::FixedInteger(i) => i.is_even(),
41            Self::BigInteger(i) => i.is_even(),
42            Self::Rational(_) => false,
43            Self::Real(_) => false,
44            Self::Complex(_) => false,
45        }
46    }
47
48    fn is_odd(&self) -> bool {
49        use num::Integer;
50        match self {
51            Self::FixedInteger(i) => i.is_odd(),
52            Self::BigInteger(i) => i.is_odd(),
53            Self::Rational(_) => false,
54            Self::Real(_) => false,
55            Self::Complex(_) => false,
56        }
57    }
58
59    fn is_complex(&self) -> bool {
60        matches!(self, Self::Complex(_))
61    }
62
63    pub fn to_u64(&self) -> u64 {
64        match self {
65            Self::FixedInteger(i) => i.to_u64().unwrap_or(0),
66            Self::BigInteger(i) => i.to_u64().unwrap_or(0),
67            Self::Rational(r) => r.to_u64().unwrap_or(0),
68            Self::Real(r) => r.to_u64().unwrap_or(0),
69            Self::Complex(c) => c.to_u64().unwrap_or(0),
70        }
71    }
72}
73
74impl From<i64> for Number {
75    fn from(i: i64) -> Self {
76        Self::FixedInteger(i)
77    }
78}
79
80impl From<Integer> for Number {
81    fn from(i: Integer) -> Self {
82        Self::BigInteger(i)
83    }
84}
85
86impl From<Rational> for Number {
87    fn from(r: Rational) -> Self {
88        Self::Rational(r)
89    }
90}
91
92impl From<f64> for Number {
93    fn from(r: f64) -> Self {
94        Self::Real(r)
95    }
96}
97
98impl From<Complex64> for Number {
99    fn from(c: Complex64) -> Self {
100        Self::Complex(c)
101    }
102}
103
104impl fmt::Display for Number {
105    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106        match self {
107            Self::FixedInteger(i) => write!(f, "{}", i),
108            Self::BigInteger(i) => write!(f, "{}", i),
109            Self::Rational(r) => write!(f, "{}", r),
110            Self::Real(r) => write!(f, "{}", r),
111            Self::Complex(c) => write!(f, "{}", c),
112        }
113    }
114}
115
116impl Neg for Number {
117    type Output = Number;
118
119    fn neg(self) -> Self {
120        match self {
121            Self::FixedInteger(i) => Self::FixedInteger(-i),
122            Self::BigInteger(i) => Self::BigInteger(-i),
123            Self::Rational(r) => Self::Rational(-r),
124            Self::Real(r) => Self::Real(-r),
125            Self::Complex(c) => Self::Complex(-c),
126        }
127    }
128}
129
130impl PartialEq for Number {
131    fn eq(&self, rhs: &Self) -> bool {
132        // TODO: A macro could probably greatly improve this
133        match (self, rhs) {
134            (Self::FixedInteger(l), Self::FixedInteger(r)) => l == r,
135            (Self::FixedInteger(l), Self::BigInteger(r)) => l == r,
136            (Self::FixedInteger(l), Self::Rational(r)) => l == r,
137            (Self::FixedInteger(l), Self::Real(r)) => Some(*l) == r.to_i64(),
138            (Self::FixedInteger(l), Self::Complex(r)) => Complex64::from_i64(*l) == Some(*r),
139            (Self::BigInteger(l), Self::FixedInteger(r)) => l == r,
140            (Self::BigInteger(l), Self::BigInteger(r)) => l == r,
141            (Self::BigInteger(l), Self::Rational(r)) => l == r,
142            (Self::BigInteger(l), Self::Real(r)) => l == r,
143            (Self::BigInteger(l), Self::Complex(r)) => {
144                <Integer as ToPrimitive>::to_f64(l).map(|l| Complex64::new(l, 0.0)) == Some(*r)
145            }
146            (Self::Rational(l), Self::FixedInteger(r)) => l == r,
147            (Self::Rational(l), Self::BigInteger(r)) => l == r,
148            (Self::Rational(l), Self::Rational(r)) => l == r,
149            (Self::Rational(l), Self::Real(r)) => <Rational as ToPrimitive>::to_f64(l) == Some(*r),
150            (Self::Rational(l), Self::Complex(r)) => {
151                <Rational as ToPrimitive>::to_f64(l).map(|l| Complex64::new(l, 0.0)) == Some(*r)
152            }
153            (Self::Real(l), Self::FixedInteger(r)) => l.to_i64() == Some(*r),
154            (Self::Real(l), Self::BigInteger(r)) => l == r,
155            (Self::Real(l), Self::Rational(r)) => l == r,
156            (Self::Real(l), Self::Real(r)) => l == r,
157            (Self::Real(l), Self::Complex(r)) => Complex64::new(*l, 0.0) == *r,
158            (Self::Complex(l), Self::FixedInteger(r)) => Some(*l) == Complex64::from_i64(*r),
159            (Self::Complex(l), Self::BigInteger(r)) => {
160                Some(*l) == <Integer as ToPrimitive>::to_f64(r).map(|r| Complex64::new(r, 0.0))
161            }
162            (Self::Complex(l), Self::Rational(r)) => {
163                Some(*l) == <Rational as ToPrimitive>::to_f64(r).map(|r| Complex64::new(r, 0.0))
164            }
165            (Self::Complex(l), Self::Real(r)) => *l == Complex64::new(*r, 0.0),
166            (Self::Complex(l), Self::Complex(r)) => l == r,
167        }
168    }
169}
170
171impl PartialOrd for Number {
172    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
173        match (self, rhs) {
174            (Self::FixedInteger(l), Self::FixedInteger(r)) => l.partial_cmp(r),
175            (Self::FixedInteger(l), Self::BigInteger(r)) => l.partial_cmp(r),
176            (Self::FixedInteger(l), Self::Rational(r)) => l.partial_cmp(r),
177            (Self::BigInteger(l), Self::FixedInteger(r)) => l.partial_cmp(r),
178            (Self::BigInteger(l), Self::BigInteger(r)) => l.partial_cmp(r),
179            (Self::BigInteger(l), Self::Rational(r)) => l.partial_cmp(r),
180            (Self::BigInteger(l), Self::Real(r)) => l.partial_cmp(r),
181            (Self::Rational(l), Self::FixedInteger(r)) => l.partial_cmp(r),
182            (Self::Rational(l), Self::BigInteger(r)) => l.partial_cmp(r),
183            (Self::Rational(l), Self::Rational(r)) => l.partial_cmp(r),
184            (Self::Rational(l), Self::Real(r)) => l.partial_cmp(r),
185            (Self::Real(l), Self::BigInteger(r)) => l.partial_cmp(r),
186            (Self::Real(l), Self::Rational(r)) => l.partial_cmp(r),
187            (Self::Real(l), Self::Real(r)) => l.partial_cmp(r),
188            (Self::Complex(_), _) | (_, Self::Complex(_)) => None,
189            // I genuinely do not know how to properly implement these. This will work for now.
190            (Self::FixedInteger(l), Self::Real(r)) => Integer::from(*l).partial_cmp(r),
191            (Self::Real(l), Self::FixedInteger(r)) => l.partial_cmp(&Integer::from(*r)),
192        }
193    }
194}
195
196macro_rules! impl_op {
197    ( $trait:ident, $op:ident, $checked_op:ident ) => {
198        impl<'a> $trait<&'a Number> for &'a Number {
199            type Output = Number;
200
201            fn $op(self, rhs: &'a Number) -> Number {
202                // TODO: A macro could probably greatly improve this
203                match (self, rhs) {
204                    (Number::FixedInteger(l), Number::FixedInteger(r)) => match l.$checked_op(*r) {
205                        Some(fixed) => Number::FixedInteger(fixed),
206                        None => Number::BigInteger(Integer::from(*l).$op(r)),
207                    },
208                    (Number::FixedInteger(l), Number::BigInteger(r)) => {
209                        Number::BigInteger(Integer::from(*l).$op(r))
210                    }
211                    (Number::FixedInteger(l), Number::Rational(r)) => {
212                        Number::Rational(Rational::from((*l, 1)).$op(r))
213                    }
214                    (Number::FixedInteger(l), Number::Real(r)) => Number::Real((*l as f64).$op(*r)),
215                    (Number::FixedInteger(l), Number::Complex(r)) => {
216                        Number::Complex(Complex64::new(*l as f64, 0.0).$op(*r))
217                    }
218                    (Number::BigInteger(l), Number::FixedInteger(r)) => {
219                        Number::BigInteger(l.$op(r).complete())
220                    }
221                    (Number::BigInteger(l), Number::BigInteger(r)) => {
222                        Number::BigInteger(l.$op(r).complete())
223                    }
224                    (Number::BigInteger(l), Number::Rational(r)) => {
225                        Number::Rational(Rational::from(l).$op(r))
226                    }
227                    (Number::BigInteger(l), Number::Real(r)) => Number::Real(l.to_f64().$op(r)),
228                    (Number::BigInteger(l), Number::Complex(r)) => {
229                        Number::Complex(Complex64::new(l.to_f64(), 0.0).$op(r))
230                    }
231                    (Number::Rational(l), Number::FixedInteger(r)) => {
232                        Number::Rational(l.$op(Rational::from((*r, 1))))
233                    }
234                    (Number::Rational(l), Number::BigInteger(r)) => {
235                        Number::Rational(l.$op(Rational::from(r)))
236                    }
237                    (Number::Rational(l), Number::Rational(r)) => {
238                        Number::Rational(l.$op(r).complete())
239                    }
240                    (Number::Rational(l), Number::Real(r)) => Number::Real(l.to_f64().$op(r)),
241                    (Number::Rational(l), Number::Complex(r)) => {
242                        Number::Complex(Complex64::new(l.to_f64(), 0.0).$op(r))
243                    }
244                    (Number::Real(l), Number::FixedInteger(r)) => Number::Real(l.$op(*r as f64)),
245                    (Number::Real(l), Number::BigInteger(r)) => Number::Real(l.$op(r.to_f64())),
246                    (Number::Real(l), Number::Rational(r)) => Number::Real(l.$op(r.to_f64())),
247                    (Number::Real(l), Number::Real(r)) => Number::Real(l.$op(r)),
248                    (Number::Real(l), Number::Complex(r)) => {
249                        Number::Complex(Complex64::new(*l, 0.0).$op(r))
250                    }
251                    (Number::Complex(l), Number::FixedInteger(r)) => {
252                        Number::Complex(l.$op(Complex64::new(*r as f64, 0.0)))
253                    }
254                    (Number::Complex(l), Number::BigInteger(r)) => {
255                        Number::Complex(l.$op(Complex64::new(r.to_f64(), 0.0)))
256                    }
257                    (Number::Complex(l), Number::Rational(r)) => {
258                        Number::Complex(l.$op(Complex64::new(r.to_f64(), 0.0)))
259                    }
260                    (Number::Complex(l), Number::Real(r)) => {
261                        Number::Complex(l.$op(Complex64::new(*r, 0.0)))
262                    }
263                    (Number::Complex(l), Number::Complex(r)) => Number::Complex(l.$op(r)),
264                }
265            }
266        }
267    };
268}
269
270impl_op!(Add, add, checked_add);
271impl_op!(Sub, sub, checked_sub);
272impl_op!(Mul, mul, checked_mul);
273
274impl<'a> Div<&'a Number> for &'a Number {
275    type Output = Number;
276
277    fn div(self, rhs: &'a Number) -> Number {
278        // TODO: A macro could probably greatly improve this
279        match (self, rhs) {
280            (Number::FixedInteger(l), Number::FixedInteger(r)) => {
281                Number::Rational(Rational::from((*l, *r)))
282            }
283            (Number::FixedInteger(l), Number::BigInteger(r)) => {
284                Number::Rational(Rational::from((*l, r)))
285            }
286            (Number::FixedInteger(l), Number::Rational(r)) => {
287                Number::Rational(Rational::from((*l, 1)) / r)
288            }
289            (Number::FixedInteger(l), Number::Real(r)) => Number::Real((*l as f64) / *r),
290            (Number::FixedInteger(l), Number::Complex(r)) => {
291                Number::Complex(Complex64::new(*l as f64, 0.0) / *r)
292            }
293            (Number::BigInteger(l), Number::FixedInteger(r)) => {
294                Number::Rational(Rational::from((l, *r)))
295            }
296            (Number::BigInteger(l), Number::BigInteger(r)) => {
297                Number::Rational(Rational::from((l, r)))
298            }
299            (Number::BigInteger(l), Number::Rational(r)) => Number::Rational(Rational::from(l) / r),
300            (Number::BigInteger(l), Number::Real(r)) => Number::Real(l.to_f64() / r),
301            (Number::BigInteger(l), Number::Complex(r)) => {
302                Number::Complex(Complex64::new(l.to_f64(), 0.0) / r)
303            }
304            (Number::Rational(l), Number::FixedInteger(r)) => {
305                Number::Rational(l / Rational::from((*r, 1)))
306            }
307            (Number::Rational(l), Number::BigInteger(r)) => Number::Rational((l / r).complete()),
308
309            (Number::Rational(l), Number::Rational(r)) => Number::Rational((l / r).complete()),
310            (Number::Rational(l), Number::Real(r)) => Number::Real(l.to_f64() / r),
311            (Number::Rational(l), Number::Complex(r)) => {
312                Number::Complex(Complex64::new(l.to_f64(), 0.0) / r)
313            }
314            (Number::Real(l), Number::FixedInteger(r)) => Number::Real(l / *r as f64),
315            (Number::Real(l), Number::BigInteger(r)) => Number::Real(l / r.to_f64()),
316            (Number::Real(l), Number::Rational(r)) => Number::Real(l / r.to_f64()),
317            (Number::Real(l), Number::Real(r)) => Number::Real(l / r),
318            (Number::Real(l), Number::Complex(r)) => Number::Complex(Complex64::new(*l, 0.0) / r),
319            (Number::Complex(l), Number::FixedInteger(r)) => {
320                Number::Complex(l / Complex64::new(*r as f64, 0.0))
321            }
322            (Number::Complex(l), Number::BigInteger(r)) => {
323                Number::Complex(l / Complex64::new(r.to_f64(), 0.0))
324            }
325            (Number::Complex(l), Number::Rational(r)) => {
326                Number::Complex(l / Complex64::new(r.to_f64(), 0.0))
327            }
328            (Number::Complex(l), Number::Real(r)) => Number::Complex(l / Complex64::new(*r, 0.0)),
329            (Number::Complex(l), Number::Complex(r)) => Number::Complex(l / r),
330        }
331    }
332}
333
334unsafe impl Trace for Number {
335    unsafe fn visit_children(&self, _visitor: fn(crate::gc::OpaqueGcPtr)) {}
336}
337
338#[builtin("zero?")]
339pub async fn zero(
340    _cont: &Option<Arc<Continuation>>,
341    arg: &Gc<Value>,
342) -> Result<Vec<Gc<Value>>, RuntimeError> {
343    let arg = arg.read().await;
344    let num: &Number = arg.as_ref().try_into()?;
345    Ok(vec![Gc::new(Value::Boolean(num.is_zero()))])
346}
347
348#[builtin("even?")]
349pub async fn even(
350    _cont: &Option<Arc<Continuation>>,
351    arg: &Gc<Value>,
352) -> Result<Vec<Gc<Value>>, RuntimeError> {
353    let arg = arg.read().await;
354    let num: &Number = arg.as_ref().try_into()?;
355    Ok(vec![Gc::new(Value::Boolean(num.is_even()))])
356}
357
358#[builtin("odd?")]
359pub async fn odd(
360    _cont: &Option<Arc<Continuation>>,
361    arg: &Gc<Value>,
362) -> Result<Vec<Gc<Value>>, RuntimeError> {
363    let arg = arg.read().await;
364    let num: &Number = arg.as_ref().try_into()?;
365    Ok(vec![Gc::new(Value::Boolean(num.is_odd()))])
366}
367
368#[builtin("+")]
369pub async fn add(
370    _cont: &Option<Arc<Continuation>>,
371    args: Vec<Gc<Value>>,
372) -> Result<Vec<Gc<Value>>, RuntimeError> {
373    let mut result = Number::FixedInteger(0);
374    for arg in args {
375        let arg = arg.read().await;
376        let num: &Number = arg.as_ref().try_into()?;
377        result = &result + num;
378    }
379    Ok(vec![Gc::new(Value::Number(result))])
380}
381
382#[builtin("-")]
383pub async fn sub(
384    _cont: &Option<Arc<Continuation>>,
385    arg1: &Gc<Value>,
386    args: Vec<Gc<Value>>,
387) -> Result<Vec<Gc<Value>>, RuntimeError> {
388    let arg1 = arg1.read().await;
389    let arg1: &Number = arg1.as_ref().try_into()?;
390    if args.is_empty() {
391        Ok(vec![Gc::new(Value::Number(-arg1.clone()))])
392    } else {
393        let mut result = arg1.clone();
394        for arg in args {
395            let arg = arg.read().await;
396            let num: &Number = arg.as_ref().try_into()?;
397            result = &result - num;
398        }
399        Ok(vec![Gc::new(Value::Number(result))])
400    }
401}
402
403#[builtin("*")]
404pub async fn mul(
405    _cont: &Option<Arc<Continuation>>,
406    args: Vec<Gc<Value>>,
407) -> Result<Vec<Gc<Value>>, RuntimeError> {
408    let mut result = Number::FixedInteger(1);
409    for arg in args {
410        let arg = arg.read().await;
411        let num: &Number = arg.as_ref().try_into()?;
412        result = &result * num;
413    }
414    Ok(vec![Gc::new(Value::Number(result))])
415}
416
417#[builtin("/")]
418pub async fn div(
419    _cont: &Option<Arc<Continuation>>,
420    arg1: &Gc<Value>,
421    args: Vec<Gc<Value>>,
422) -> Result<Vec<Gc<Value>>, RuntimeError> {
423    let arg1 = arg1.read().await;
424    let arg1: &Number = arg1.as_ref().try_into()?;
425    if arg1.is_zero() {
426        return Err(RuntimeError::division_by_zero());
427    }
428    let mut result = &Number::FixedInteger(1) / arg1;
429    for arg in args {
430        let arg = arg.read().await;
431        let num: &Number = arg.as_ref().try_into()?;
432        if num.is_zero() {
433            return Err(RuntimeError::division_by_zero());
434        }
435        result = &result / num;
436    }
437    Ok(vec![Gc::new(Value::Number(result))])
438}
439
440#[builtin("=")]
441pub async fn equals(
442    _cont: &Option<Arc<Continuation>>,
443    args: Vec<Gc<Value>>,
444) -> Result<Vec<Gc<Value>>, RuntimeError> {
445    if let Some((first, rest)) = args.split_first() {
446        let first = first.read().await;
447        let first: &Number = first.as_ref().try_into()?;
448        for next in rest {
449            let next = next.read().await;
450            let next: &Number = next.as_ref().try_into()?;
451            if first != next {
452                return Ok(vec![Gc::new(Value::Boolean(false))]);
453            }
454        }
455    }
456    Ok(vec![Gc::new(Value::Boolean(true))])
457}
458
459#[builtin(">")]
460pub async fn greater(
461    _cont: &Option<Arc<Continuation>>,
462    args: Vec<Gc<Value>>,
463) -> Result<Vec<Gc<Value>>, RuntimeError> {
464    if let Some((head, rest)) = args.split_first() {
465        let mut prev = head.clone();
466        for next in rest {
467            {
468                let prev = prev.read().await;
469                let next = next.read().await;
470                let prev: &Number = prev.as_ref().try_into()?;
471                let next: &Number = next.as_ref().try_into()?;
472                // This is somewhat less efficient for small numbers but avoids
473                // cloning big ones
474                if prev.is_complex() {
475                    return Err(RuntimeError::invalid_type("number", "complex"));
476                }
477                if next.is_complex() {
478                    return Err(RuntimeError::invalid_type("number", "complex"));
479                }
480                if prev <= next {
481                    return Ok(vec![Gc::new(Value::Boolean(false))]);
482                }
483            }
484            prev = next.clone();
485        }
486    }
487    Ok(vec![Gc::new(Value::Boolean(true))])
488}
489
490#[builtin(">=")]
491pub async fn greater_equal(
492    _cont: &Option<Arc<Continuation>>,
493    args: Vec<Gc<Value>>,
494) -> Result<Vec<Gc<Value>>, RuntimeError> {
495    if let Some((head, rest)) = args.split_first() {
496        let mut prev = head.clone();
497        for next in rest {
498            {
499                let prev = prev.read().await;
500                let next = next.read().await;
501                let prev: &Number = prev.as_ref().try_into()?;
502                let next: &Number = next.as_ref().try_into()?;
503                if prev.is_complex() {
504                    return Err(RuntimeError::invalid_type("number", "complex"));
505                }
506                if next.is_complex() {
507                    return Err(RuntimeError::invalid_type("number", "complex"));
508                }
509                if prev < next {
510                    return Ok(vec![Gc::new(Value::Boolean(false))]);
511                }
512            }
513            prev = next.clone();
514        }
515    }
516    Ok(vec![Gc::new(Value::Boolean(true))])
517}
518
519#[builtin("<")]
520pub async fn lesser(
521    _cont: &Option<Arc<Continuation>>,
522    args: Vec<Gc<Value>>,
523) -> Result<Vec<Gc<Value>>, RuntimeError> {
524    if let Some((head, rest)) = args.split_first() {
525        let mut prev = head.clone();
526        for next in rest {
527            {
528                let prev = prev.read().await;
529                let next = next.read().await;
530                let prev: &Number = prev.as_ref().try_into()?;
531                let next: &Number = next.as_ref().try_into()?;
532                if prev.is_complex() {
533                    return Err(RuntimeError::invalid_type("number", "complex"));
534                }
535                if next.is_complex() {
536                    return Err(RuntimeError::invalid_type("number", "complex"));
537                }
538                if prev >= next {
539                    return Ok(vec![Gc::new(Value::Boolean(false))]);
540                }
541            }
542            prev = next.clone();
543        }
544    }
545    Ok(vec![Gc::new(Value::Boolean(true))])
546}
547
548#[builtin("<=")]
549pub async fn lesser_equal(
550    _cont: &Option<Arc<Continuation>>,
551    args: Vec<Gc<Value>>,
552) -> Result<Vec<Gc<Value>>, RuntimeError> {
553    if let Some((head, rest)) = args.split_first() {
554        let mut prev = head.clone();
555        for next in rest {
556            {
557                let prev = prev.read().await;
558                let next = next.read().await;
559                let prev: &Number = prev.as_ref().try_into()?;
560                let next: &Number = next.as_ref().try_into()?;
561                if prev.is_complex() {
562                    return Err(RuntimeError::invalid_type("number", "complex"));
563                }
564                if next.is_complex() {
565                    return Err(RuntimeError::invalid_type("number", "complex"));
566                }
567                if prev > next {
568                    return Ok(vec![Gc::new(Value::Boolean(false))]);
569                }
570            }
571            prev = next.clone();
572        }
573    }
574    Ok(vec![Gc::new(Value::Boolean(true))])
575}
576
577#[builtin("number?")]
578pub async fn is_number(
579    _cont: &Option<Arc<Continuation>>,
580    arg: &Gc<Value>,
581) -> Result<Vec<Gc<Value>>, RuntimeError> {
582    let arg = arg.read().await;
583    Ok(vec![Gc::new(Value::Boolean(matches!(
584        &*arg,
585        Value::Number(_)
586    )))])
587}
588
589#[builtin("integer?")]
590pub async fn is_integer(
591    _cont: &Option<Arc<Continuation>>,
592    arg: &Gc<Value>,
593) -> Result<Vec<Gc<Value>>, RuntimeError> {
594    let arg = arg.read().await;
595    Ok(vec![Gc::new(Value::Boolean(matches!(
596        &*arg,
597        Value::Number(Number::FixedInteger(_)) | Value::Number(Number::BigInteger(_))
598    )))])
599}
600
601#[builtin("rational?")]
602pub async fn is_rational(
603    _cont: &Option<Arc<Continuation>>,
604    arg: &Gc<Value>,
605) -> Result<Vec<Gc<Value>>, RuntimeError> {
606    let arg = arg.read().await;
607    Ok(vec![Gc::new(Value::Boolean(matches!(
608        &*arg,
609        Value::Number(Number::Rational(_))
610    )))])
611}
612
613#[builtin("real?")]
614pub async fn is_real(
615    _cont: &Option<Arc<Continuation>>,
616    arg: &Gc<Value>,
617) -> Result<Vec<Gc<Value>>, RuntimeError> {
618    let arg = arg.read().await;
619    Ok(vec![Gc::new(Value::Boolean(matches!(
620        &*arg,
621        Value::Number(Number::Real(_))
622    )))])
623}
624
625#[builtin("complex?")]
626pub async fn is_complex(
627    _cont: &Option<Arc<Continuation>>,
628    arg: &Gc<Value>,
629) -> Result<Vec<Gc<Value>>, RuntimeError> {
630    let arg = arg.read().await;
631    Ok(vec![Gc::new(Value::Boolean(matches!(
632        &*arg,
633        Value::Number(Number::Complex(_))
634    )))])
635}