Skip to main content

logicaffeine_data/
exact.rs

1//! The value a compiled LOGOS program holds wherever the exact extension reaches: real algebraic
2//! numbers, computable reals, the infinitesimal and the hyperreals it generates, infinite integers,
3//! ordinals, residue-dependent and provisional values — and every standard value that meets them.
4//!
5//! [`LogosValue`] is the compiled counterpart of the interpreter's runtime value on exactly that
6//! ground. It keeps each value in its canonical form, so a variable whose value is an `Int` still
7//! divides, promotes to a big integer and prints as an `Int`, and a binding widened to hold a
8//! hyperreal later means what it meant before. How the exact types mix is
9//! [`logicaffeine_base::tower`], and the supertask runtime is [`logicaffeine_base::supertask`],
10//! both generic over the value model: this module gives them this one. The standard rules here —
11//! integers that promote instead of wrapping, `/` that truncates two integers, exact rationals, IEEE
12//! floats, text that concatenates — are the interpreter's, sentence for sentence, held together by
13//! the value-model differential in the test suite.
14
15use std::cmp::Ordering;
16use std::fmt;
17use std::sync::Arc;
18
19use logicaffeine_base::algebraic::Algebraic;
20use logicaffeine_base::exact_real::ExactReal;
21use logicaffeine_base::limit_value::Converging;
22use logicaffeine_base::numeric::{
23    cmp_bigint_f64_exact, cmp_i64_f64_exact, cmp_rational_f64_exact, float_max, float_min,
24    rational_from_f64_exact, BigInt, Decimal, Rational,
25};
26use logicaffeine_base::ordinal::Ordinal;
27use logicaffeine_base::tower::{
28    self, DependsValue, ExactRef, HyperValue, NaturalValue, Op, Rounding, Shape, TowerValue,
29    ValueAlgebra,
30};
31
32/// A comparison, as a compiled program names it.
33pub use logicaffeine_base::tower::Rel;
34
35use crate::failure::{answered, index_out_of_bounds, DIVISION_BY_ZERO, MODULO_BY_ZERO};
36
37/// A builtin of the exact extension, as a compiled program names it.
38pub use logicaffeine_base::extension::Builtin as ExtensionBuiltin;
39
40/// `builtin` applied to `args` in a compiled program: [`logicaffeine_base::extension::call`] on this
41/// value model, the interpreter's own dispatcher, stopping with its refusal.
42pub fn logos_extension(builtin: ExtensionBuiltin, args: Vec<LogosValue>) -> LogosValue {
43    answered(logicaffeine_base::extension::call(builtin, args))
44}
45
46/// The integer and rational types, by names the value's own variants do not shadow.
47type Integer = BigInt;
48type Ratio = Rational;
49
50/// A value of a compiled program where the exact extension reaches. See the module documentation.
51#[derive(Clone, Debug)]
52pub enum LogosValue {
53    Int(i64),
54    /// An integer outside `i64`; never one that fits.
55    BigInt(Arc<BigInt>),
56    /// A rational that is not whole.
57    Rational(Arc<Rational>),
58    Float(f64),
59    Decimal(Arc<Decimal>),
60    Bool(bool),
61    Text(Arc<str>),
62    Nothing,
63    List(Arc<Vec<LogosValue>>),
64    Tuple(Arc<Vec<LogosValue>>),
65    Algebraic(Arc<Algebraic>),
66    ExactReal(Arc<ExactReal>),
67    Hyperreal(Arc<HyperValue>),
68    Hypernatural(Arc<NaturalValue>),
69    Ordinal(Arc<Ordinal>),
70    Depends(Arc<DependsValue<LogosValue>>),
71    Converging(Arc<Converging<LogosValue>>),
72    /// A value of a kind the exact types do not mix with — a date, a span of time, a moment — held
73    /// as its own compiled value, which prints, compares and combines as the interpreter's does.
74    Other(Arc<dyn OtherValue>),
75}
76
77/// A compiled value of a kind outside the exact tower, as a [`LogosValue`] holds it: each answers for
78/// itself how it prints, what it equals, how it orders and what it combines with, exactly as the
79/// interpreter's value of that kind does. A pair it has no arm for is refused in the interpreter's
80/// words by the caller.
81pub trait OtherValue: fmt::Debug + Send + Sync + 'static {
82    /// The kind's name as the language writes it.
83    fn type_name(&self) -> &str;
84    /// How the value prints.
85    fn display_string(&self) -> String;
86    /// The value, for a kind to recognise one of its own.
87    fn as_any(&self) -> &dyn std::any::Any;
88    /// The language's equality with another value of a kind outside the tower.
89    fn equals(&self, o: &dyn OtherValue) -> bool;
90    /// The order of `self` against `o`, `None` when the language orders no such pair.
91    fn order(&self, o: &LogosValue) -> Option<Option<Ordering>>;
92    /// `self op o`, or `o op self` when `reversed`; `None` when the language has no arm for the pair.
93    fn combine(&self, op: Op, o: &LogosValue, reversed: bool) -> Option<Result<LogosValue, String>>;
94}
95
96impl LogosValue {
97    /// An integer in its smallest form.
98    pub fn from_bigint(b: BigInt) -> LogosValue {
99        match b.to_i64() {
100            Some(n) => LogosValue::Int(n),
101            None => LogosValue::BigInt(Arc::new(b)),
102        }
103    }
104
105    /// A rational in its smallest form: an integer when it is whole.
106    pub fn from_rational(r: Rational) -> LogosValue {
107        if r.is_integer() {
108            return LogosValue::from_bigint(r.to_bigint().expect("a whole rational is an integer"));
109        }
110        LogosValue::Rational(Arc::new(r))
111    }
112
113    /// Text.
114    pub fn text(t: &str) -> LogosValue {
115        LogosValue::Text(Arc::from(t))
116    }
117
118    /// A list.
119    pub fn list(items: Vec<LogosValue>) -> LogosValue {
120        LogosValue::List(Arc::new(items))
121    }
122
123    /// A value of a kind outside the exact tower.
124    pub fn other(v: impl OtherValue) -> LogosValue {
125        LogosValue::Other(Arc::new(v))
126    }
127
128    /// The compiled value of a kind outside the tower this holds, when it holds one of that kind.
129    pub fn other_as<T: OtherValue>(&self) -> Option<&T> {
130        match self {
131            LogosValue::Other(v) => v.as_any().downcast_ref::<T>(),
132            _ => None,
133        }
134    }
135
136    /// `a op b` where either side is of a kind outside the tower: the kind's own arm.
137    fn other_arith(&self, op: Op, o: &LogosValue) -> Option<Result<LogosValue, String>> {
138        if let LogosValue::Other(a) = self {
139            if let Some(r) = a.combine(op, o, false) {
140                return Some(r);
141            }
142        }
143        match o {
144            LogosValue::Other(b) => b.combine(op, self, true),
145            _ => None,
146        }
147    }
148
149    /// The program's infinitesimal named `name`, its reciprocal's residues modulo `modulus` limited
150    /// to `allowed`.
151    pub fn infinitesimal(name: &str, modulus: i64, allowed: &[i64]) -> Result<LogosValue, String> {
152        let allowed: Vec<u64> = allowed.iter().map(|r| *r as u64).collect();
153        tower::new_infinitesimal(name, modulus as u64, &allowed)
154    }
155
156    /// The value's type as the language names it.
157    pub fn type_name(&self) -> &str {
158        match self {
159            LogosValue::Int(_) | LogosValue::BigInt(_) => "Int",
160            LogosValue::Rational(_) => "Rational",
161            LogosValue::Float(_) => "Float",
162            LogosValue::Decimal(_) => "Decimal",
163            LogosValue::Bool(_) => "Bool",
164            LogosValue::Text(_) => "Text",
165            LogosValue::Nothing => "Nothing",
166            LogosValue::List(_) => "List",
167            LogosValue::Tuple(_) => "Tuple",
168            LogosValue::Algebraic(_) => "Algebraic",
169            LogosValue::ExactReal(_) => "ExactReal",
170            LogosValue::Hyperreal(_) => "Hyperreal",
171            LogosValue::Hypernatural(_) => "Hypernatural",
172            LogosValue::Ordinal(_) => "Ordinal",
173            LogosValue::Depends(_) => "Depends",
174            LogosValue::Converging(_) => "Converging",
175            LogosValue::Other(v) => v.type_name(),
176        }
177    }
178
179    /// How the value prints.
180    pub fn display_string(&self) -> String {
181        match self {
182            LogosValue::Int(n) => n.to_string(),
183            LogosValue::BigInt(b) => b.to_string(),
184            LogosValue::Rational(r) => r.to_string(),
185            LogosValue::Float(f) => crate::fmt::fmt_f64(*f),
186            LogosValue::Decimal(d) => d.to_string(),
187            LogosValue::Bool(b) => if *b { "true" } else { "false" }.to_string(),
188            LogosValue::Text(t) => t.to_string(),
189            LogosValue::Nothing => "nothing".to_string(),
190            LogosValue::List(items) => format!(
191                "[{}]",
192                items.iter().map(LogosValue::display_string).collect::<Vec<_>>().join(", ")
193            ),
194            LogosValue::Tuple(items) => format!(
195                "({})",
196                items.iter().map(LogosValue::display_string).collect::<Vec<_>>().join(", ")
197            ),
198            LogosValue::Other(v) => v.display_string(),
199            exact => tower::display(exact).expect("an exact value displays"),
200        }
201    }
202
203    /// The truth a condition reads: a residue-dependent answer, or a provisional one no proof
204    /// settled, is refused with the sentence every tier gives.
205    pub fn decided_truth(&self) -> Result<bool, String> {
206        if let Some(why) = tower::undecided_branch(self) {
207            return Err(why);
208        }
209        Ok(self.is_truthy())
210    }
211
212    fn is_truthy(&self) -> bool {
213        match self {
214            LogosValue::Bool(b) => *b,
215            LogosValue::Int(n) => *n != 0,
216            LogosValue::Float(f) => *f != 0.0,
217            LogosValue::BigInt(b) => !b.is_zero(),
218            LogosValue::Rational(r) => !r.is_zero(),
219            LogosValue::Decimal(d) => !d.is_zero(),
220            LogosValue::Text(t) => !t.is_empty(),
221            LogosValue::List(items) => !items.is_empty(),
222            LogosValue::Nothing => false,
223            _ => true,
224        }
225    }
226
227    fn big(&self) -> Option<BigInt> {
228        match self {
229            LogosValue::Int(n) => Some(BigInt::from_i64(*n)),
230            LogosValue::BigInt(b) => Some((**b).clone()),
231            _ => None,
232        }
233    }
234
235    fn rat(&self) -> Option<Rational> {
236        match self {
237            LogosValue::Int(n) => Some(Rational::from_i64(*n)),
238            LogosValue::BigInt(b) => Some(Rational::from_bigint((**b).clone())),
239            LogosValue::Rational(r) => Some((**r).clone()),
240            LogosValue::Decimal(d) => Some(d.to_rational()),
241            _ => None,
242        }
243    }
244
245    fn dec(&self) -> Option<Decimal> {
246        match self {
247            LogosValue::Int(n) => Some(Decimal::from_i64(*n)),
248            LogosValue::BigInt(b) => Some(Decimal::from_bigint((**b).clone())),
249            LogosValue::Decimal(d) => Some((**d).clone()),
250            _ => None,
251        }
252    }
253
254    fn f64(&self) -> Option<f64> {
255        match self {
256            LogosValue::Int(n) => Some(*n as f64),
257            LogosValue::BigInt(b) => Some(b.to_f64()),
258            LogosValue::Rational(r) => Some(r.to_f64()),
259            LogosValue::Decimal(d) => Some(d.to_rational().to_f64()),
260            LogosValue::Float(f) => Some(*f),
261            _ => None,
262        }
263    }
264
265    fn is_decimal(&self) -> bool {
266        matches!(self, LogosValue::Decimal(_))
267    }
268
269    fn is_float(&self) -> bool {
270        matches!(self, LogosValue::Float(_))
271    }
272
273    /// `+`, `−` or `×` of two decimals, or of a decimal and an integer, a rational, a float.
274    fn decimal_op(
275        &self,
276        o: &LogosValue,
277        dec: impl Fn(&Decimal, &Decimal) -> Decimal,
278        rat: impl Fn(&Rational, &Rational) -> Rational,
279        flt: impl Fn(f64, f64) -> f64,
280    ) -> Option<LogosValue> {
281        if !self.is_decimal() && !o.is_decimal() {
282            return None;
283        }
284        if let (Some(a), Some(b)) = (self.dec(), o.dec()) {
285            return Some(LogosValue::Decimal(Arc::new(dec(&a, &b))));
286        }
287        if let (Some(a), Some(b)) = (self.rat(), o.rat()) {
288            return Some(LogosValue::from_rational(rat(&a, &b)));
289        }
290        Some(LogosValue::Float(flt(self.f64()?, o.f64()?)))
291    }
292
293    /// `+`, `−` or `×` of the numeric tower: exact integers that promote, exact rationals, a float
294    /// operand making the result a float. `None` when either side is not a number.
295    fn tower_op(
296        &self,
297        o: &LogosValue,
298        int: impl Fn(i64, i64) -> Option<i64>,
299        big: impl Fn(&BigInt, &BigInt) -> BigInt,
300        rat: impl Fn(&Rational, &Rational) -> Rational,
301        flt: impl Fn(f64, f64) -> f64,
302    ) -> Option<LogosValue> {
303        use LogosValue::*;
304        Some(match (self, o) {
305            (Int(a), Int(b)) => match int(*a, *b) {
306                Some(n) => Int(n),
307                None => LogosValue::from_bigint(big(&Integer::from_i64(*a), &Integer::from_i64(*b))),
308            },
309            (Int(_) | BigInt(_), Int(_) | BigInt(_)) => {
310                LogosValue::from_bigint(big(&self.big()?, &o.big()?))
311            }
312            (Float(_), Int(_) | BigInt(_) | Float(_) | Rational(_))
313            | (Int(_) | BigInt(_) | Rational(_), Float(_)) => Float(flt(self.f64()?, o.f64()?)),
314            (Rational(_), Int(_) | BigInt(_) | Rational(_)) | (Int(_) | BigInt(_), Rational(_)) => {
315                LogosValue::from_rational(rat(&self.rat()?, &o.rat()?))
316            }
317            _ => return None,
318        })
319    }
320
321    fn arith(op: Op, a: LogosValue, b: LogosValue) -> Result<LogosValue, String> {
322        match op {
323            Op::Add => a.add(&b),
324            Op::Sub => a.sub(&b),
325            Op::Mul => a.mul(&b),
326            Op::Div => a.div(&b),
327            Op::ExactDiv => a.exact_div(&b),
328            Op::FloorDiv => a.floor_div(&b),
329            Op::Mod => a.rem(&b),
330            Op::Pow => a.pow(&b),
331        }
332    }
333
334    /// `a + b`.
335    pub fn add(&self, o: &LogosValue) -> Result<LogosValue, String> {
336        if let Some(r) = tower::arith(Op::Add, self, o, &LogosValue::arith) {
337            return r;
338        }
339        if let Some(r) = self.decimal_op(o, |a, b| a.add(b), |a, b| a.add(b), |a, b| a + b) {
340            return Ok(r);
341        }
342        if let Some(r) = self.tower_op(o, i64::checked_add, BigInt::add, Rational::add, |a, b| a + b) {
343            return Ok(r);
344        }
345        if let Some(r) = self.other_arith(Op::Add, o) {
346            return r;
347        }
348        match (self, o) {
349            (LogosValue::Text(a), LogosValue::Text(b)) => Ok(LogosValue::text(&format!("{a}{b}"))),
350            (LogosValue::Text(a), other) => Ok(LogosValue::text(&format!("{a}{}", other.display_string()))),
351            (other, LogosValue::Text(b)) => Ok(LogosValue::text(&format!("{}{b}", other.display_string()))),
352            (LogosValue::List(a), LogosValue::List(b)) => {
353                Ok(LogosValue::list(a.iter().chain(b.iter()).cloned().collect()))
354            }
355            _ => Err(format!("Cannot add {} and {}", self.type_name(), o.type_name())),
356        }
357    }
358
359    /// `a − b`.
360    pub fn sub(&self, o: &LogosValue) -> Result<LogosValue, String> {
361        if let Some(r) = tower::arith(Op::Sub, self, o, &LogosValue::arith) {
362            return r;
363        }
364        if let Some(r) = self.decimal_op(o, |a, b| a.sub(b), |a, b| a.sub(b), |a, b| a - b) {
365            return Ok(r);
366        }
367        if let Some(r) = self.tower_op(o, i64::checked_sub, BigInt::sub, Rational::sub, |a, b| a - b) {
368            return Ok(r);
369        }
370        if let Some(r) = self.other_arith(Op::Sub, o) {
371            return r;
372        }
373        Err(format!("Cannot subtract {} from {}", o.type_name(), self.type_name()))
374    }
375
376    /// `a × b`.
377    pub fn mul(&self, o: &LogosValue) -> Result<LogosValue, String> {
378        if let Some(r) = tower::arith(Op::Mul, self, o, &LogosValue::arith) {
379            return r;
380        }
381        if let Some(r) = self.decimal_op(o, |a, b| a.mul(b), |a, b| a.mul(b), |a, b| a * b) {
382            return Ok(r);
383        }
384        if let Some(r) = self.tower_op(o, i64::checked_mul, BigInt::mul, Rational::mul, |a, b| a * b) {
385            return Ok(r);
386        }
387        match (self, o) {
388            (LogosValue::List(items), LogosValue::Int(n)) | (LogosValue::Int(n), LogosValue::List(items)) => {
389                let count = (*n).max(0) as usize;
390                let mut out = Vec::with_capacity(items.len() * count);
391                for _ in 0..count {
392                    out.extend(items.iter().cloned());
393                }
394                Ok(LogosValue::list(out))
395            }
396            _ => Err(format!("Cannot multiply {} and {}", self.type_name(), o.type_name())),
397        }
398    }
399
400    /// The polymorphic `/`: two integers truncate, a rational divides exactly, a float divides as a
401    /// float, the exact types divide in their field.
402    pub fn div(&self, o: &LogosValue) -> Result<LogosValue, String> {
403        use LogosValue::*;
404        if let Some(r) = tower::arith(Op::Div, self, o, &LogosValue::arith) {
405            return r;
406        }
407        if self.is_decimal() || o.is_decimal() {
408            if let (Some(a), Some(b)) = (self.rat(), o.rat()) {
409                return a
410                    .div(&b)
411                    .map(LogosValue::from_rational)
412                    .ok_or_else(|| DIVISION_BY_ZERO.to_string());
413            }
414            if let (Some(a), Some(b)) = (self.f64(), o.f64()) {
415                if b == 0.0 {
416                    return Err(DIVISION_BY_ZERO.to_string());
417                }
418                return Ok(Float(a / b));
419            }
420        }
421        match (self, o) {
422            (Int(a), Int(b)) => {
423                if *b == 0 {
424                    return Err(DIVISION_BY_ZERO.to_string());
425                }
426                Ok(match a.checked_div(*b) {
427                    Some(q) => Int(q),
428                    None => LogosValue::from_bigint(
429                        Integer::from_i64(*a).div_rem(&Integer::from_i64(*b)).expect("nonzero divisor").0,
430                    ),
431                })
432            }
433            (Int(_) | BigInt(_), Int(_) | BigInt(_)) => {
434                let (a, b) = (self.big().expect("integer"), o.big().expect("integer"));
435                if b.is_zero() {
436                    return Err(DIVISION_BY_ZERO.to_string());
437                }
438                Ok(LogosValue::from_bigint(a.div_rem(&b).expect("nonzero divisor").0))
439            }
440            (Float(_), Float(_) | Int(_) | BigInt(_) | Rational(_))
441            | (Int(_) | BigInt(_) | Rational(_), Float(_)) => {
442                let (a, b) = (self.f64().expect("number"), o.f64().expect("number"));
443                let divisor_is_zero = match o {
444                    Int(n) => *n == 0,
445                    BigInt(_) | Rational(_) => false,
446                    _ => b == 0.0,
447                };
448                if divisor_is_zero {
449                    return Err(DIVISION_BY_ZERO.to_string());
450                }
451                Ok(Float(a / b))
452            }
453            (Rational(_), Int(_) | BigInt(_) | Rational(_)) | (Int(_) | BigInt(_), Rational(_)) => self
454                .rat()
455                .expect("rational")
456                .div(&o.rat().expect("rational"))
457                .map(LogosValue::from_rational)
458                .ok_or_else(|| DIVISION_BY_ZERO.to_string()),
459            _ => Err(format!("Cannot divide {} by {}", self.type_name(), o.type_name())),
460        }
461    }
462
463    /// `/` in an exact context: every integer and rational divides exactly; a float defers to `/`.
464    pub fn exact_div(&self, o: &LogosValue) -> Result<LogosValue, String> {
465        if let Some(r) = tower::arith(Op::ExactDiv, self, o, &LogosValue::arith) {
466            return r;
467        }
468        if let (Some(a), Some(b)) = (self.rat(), o.rat()) {
469            return a
470                .div(&b)
471                .map(LogosValue::from_rational)
472                .ok_or_else(|| DIVISION_BY_ZERO.to_string());
473        }
474        if self.is_float() || o.is_float() {
475            return self.div(o);
476        }
477        Err(format!("Cannot divide {} by {}", self.type_name(), o.type_name()))
478    }
479
480    /// Floor division.
481    pub fn floor_div(&self, o: &LogosValue) -> Result<LogosValue, String> {
482        if let Some(r) = tower::arith(Op::FloorDiv, self, o, &LogosValue::arith) {
483            return r;
484        }
485        if self.is_float() || o.is_float() {
486            if let (Some(a), Some(b)) = (self.f64(), o.f64()) {
487                if b == 0.0 {
488                    return Err(DIVISION_BY_ZERO.to_string());
489                }
490                return Ok(LogosValue::Float((a / b).floor()));
491            }
492        }
493        if let (Some(a), Some(b)) = (self.rat(), o.rat()) {
494            return a
495                .div(&b)
496                .map(|q| LogosValue::from_bigint(q.floor()))
497                .ok_or_else(|| DIVISION_BY_ZERO.to_string());
498        }
499        Err(format!("Cannot floor-divide {} by {}", self.type_name(), o.type_name()))
500    }
501
502    /// The remainder of two integers, its sign the dividend's.
503    pub fn rem(&self, o: &LogosValue) -> Result<LogosValue, String> {
504        use LogosValue::*;
505        if let Some(r) = tower::arith(Op::Mod, self, o, &LogosValue::arith) {
506            return r;
507        }
508        match (self, o) {
509            (Int(a), Int(b)) => {
510                if *b == 0 {
511                    return Err(MODULO_BY_ZERO.to_string());
512                }
513                Ok(Int(a.checked_rem(*b).unwrap_or(0)))
514            }
515            (Int(_) | BigInt(_), Int(_) | BigInt(_)) => {
516                let (a, b) = (self.big().expect("integer"), o.big().expect("integer"));
517                if b.is_zero() {
518                    return Err(MODULO_BY_ZERO.to_string());
519                }
520                Ok(LogosValue::from_bigint(a.div_rem(&b).expect("nonzero divisor").1))
521            }
522            _ => Err(format!(
523                "Cannot compute modulo of {} and {}",
524                self.type_name(),
525                o.type_name()
526            )),
527        }
528    }
529
530    /// `base ^ exponent`.
531    pub fn pow(&self, o: &LogosValue) -> Result<LogosValue, String> {
532        use LogosValue::*;
533        if let Some(r) = tower::arith(Op::Pow, self, o, &LogosValue::arith) {
534            return r;
535        }
536        if self.is_float() || o.is_float() {
537            let b = self
538                .f64()
539                .ok_or_else(|| format!("cannot raise {} to a power", self.type_name()))?;
540            let e = o
541                .f64()
542                .ok_or_else(|| format!("cannot raise to a {} power", o.type_name()))?;
543            return Ok(Float(b.powf(e)));
544        }
545        match (self, o) {
546            (Int(b), Int(e)) => {
547                if *e < 0 {
548                    return Err(
549                        "negative exponent on an integer (an Int can't hold a fraction — use a Float base)"
550                            .to_string(),
551                    );
552                }
553                let e = u32::try_from(*e).map_err(|_| "exponent too large".to_string())?;
554                Ok(match b.checked_pow(e) {
555                    Some(r) => Int(r),
556                    None => LogosValue::from_bigint(Integer::from_i64(*b).pow(e)),
557                })
558            }
559            (BigInt(b), Int(e)) => {
560                let e = u32::try_from(*e).map_err(|_| {
561                    "negative or too-large exponent on an integer (use a Float base)".to_string()
562                })?;
563                Ok(LogosValue::from_bigint(b.pow(e)))
564            }
565            (Rational(b), Int(e)) => {
566                let e = i32::try_from(*e).map_err(|_| "exponent too large".to_string())?;
567                b.pow(e)
568                    .map(LogosValue::from_rational)
569                    .ok_or_else(|| "zero raised to a negative power".to_string())
570            }
571            _ => Err(format!(
572                "cannot raise {} to the {} power",
573                self.type_name(),
574                o.type_name()
575            )),
576        }
577    }
578
579    fn relate(rel: Rel, a: LogosValue, b: LogosValue) -> Result<LogosValue, String> {
580        a.relation(rel, &b)
581    }
582
583    /// `a rel b`: a `Bool`, or a residue-dependent one where the answer depends on `⌈1/dt⌉`.
584    pub fn relation(&self, rel: Rel, o: &LogosValue) -> Result<LogosValue, String> {
585        if let Some(r) = tower::relation(rel, self, o, &LogosValue::relate) {
586            return r;
587        }
588        match rel {
589            Rel::Eq => Ok(LogosValue::Bool(self.values_equal(o))),
590            Rel::NotEq => Ok(LogosValue::Bool(!self.values_equal(o))),
591            _ => self.order(o).map(|ord| {
592                LogosValue::Bool(ord.is_some_and(|o| match rel {
593                    Rel::Lt => o == Ordering::Less,
594                    Rel::Gt => o == Ordering::Greater,
595                    Rel::LtEq => o != Ordering::Greater,
596                    Rel::GtEq => o != Ordering::Less,
597                    Rel::Eq | Rel::NotEq => unreachable!("handled above"),
598                }))
599            }),
600        }
601    }
602
603    /// The order of two standard numbers, `None` for an unordered float; a refusal for anything
604    /// else.
605    fn order(&self, o: &LogosValue) -> Result<Option<Ordering>, String> {
606        use LogosValue::*;
607        Ok(match (self, o) {
608            (Int(a), Int(b)) => Some(a.cmp(b)),
609            (Int(_) | BigInt(_), Int(_) | BigInt(_)) => {
610                Some(self.big().expect("integer").cmp(&o.big().expect("integer")))
611            }
612            (BigInt(a), Float(b)) => cmp_bigint_f64_exact(a, *b),
613            (Float(a), BigInt(b)) => cmp_bigint_f64_exact(b, *a).map(Ordering::reverse),
614            (Rational(_), Int(_) | BigInt(_) | Rational(_)) | (Int(_) | BigInt(_), Rational(_)) => {
615                Some(self.rat().expect("rational").cmp(&o.rat().expect("rational")))
616            }
617            (Rational(a), Float(b)) => cmp_rational_f64_exact(a, *b),
618            (Float(a), Rational(b)) => cmp_rational_f64_exact(b, *a).map(Ordering::reverse),
619            (Float(a), Float(b)) => a.partial_cmp(b),
620            (Int(a), Float(b)) => cmp_i64_f64_exact(*a, *b),
621            (Float(a), Int(b)) => cmp_i64_f64_exact(*b, *a).map(Ordering::reverse),
622            (Other(a), _) if a.order(o).is_some() => a.order(o).expect("checked"),
623            (_, Other(b)) if b.order(self).is_some() => b.order(self).expect("checked").map(Ordering::reverse),
624            (l, r) if l.is_decimal() || r.is_decimal() => match (l.rat(), r.rat()) {
625                (Some(a), Some(b)) => Some(a.cmp(&b)),
626                _ => match (l.f64(), r.f64()) {
627                    (Some(a), Some(b)) => a.partial_cmp(&b),
628                    _ => {
629                        return Err(format!(
630                            "Cannot compare {} and {}",
631                            l.type_name(),
632                            r.type_name()
633                        ))
634                    }
635                },
636            },
637            _ => {
638                return Err(format!(
639                    "Cannot compare {} and {}",
640                    self.type_name(),
641                    o.type_name()
642                ))
643            }
644        })
645    }
646
647    /// The language's equality: exact across numeric types, structural on lists and tuples.
648    pub fn values_equal(&self, o: &LogosValue) -> bool {
649        use LogosValue::*;
650        if let Some(same) = tower::structurally_equal(self, o) {
651            return same;
652        }
653        match (self, o) {
654            (Int(a), Int(b)) => a == b,
655            (BigInt(a), BigInt(b)) => a == b,
656            (Rational(a), Rational(b)) => a == b,
657            (Decimal(a), Decimal(b)) => a == b,
658            (Float(a), Float(b)) => a == b,
659            (Int(a), Float(b)) | (Float(b), Int(a)) => {
660                cmp_i64_f64_exact(*a, *b) == Some(Ordering::Equal)
661            }
662            (BigInt(a), Float(b)) | (Float(b), BigInt(a)) => {
663                cmp_bigint_f64_exact(a, *b) == Some(Ordering::Equal)
664            }
665            (Rational(a), Float(b)) | (Float(b), Rational(a)) => {
666                cmp_rational_f64_exact(a, *b) == Some(Ordering::Equal)
667            }
668            (Bool(a), Bool(b)) => a == b,
669            (Text(a), Text(b)) => a == b,
670            (Nothing, Nothing) => true,
671            (List(a), List(b)) | (Tuple(a), Tuple(b)) => {
672                a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.values_equal(y))
673            }
674            (Other(a), Other(b)) => a.equals(&**b),
675            _ => false,
676        }
677    }
678
679    /// `not v`, lifted over residue branches and through provisional values.
680    pub fn not(&self) -> Result<LogosValue, String> {
681        if let Some(r) = tower::not(self, &|v| v.not()) {
682            return r;
683        }
684        Ok(LogosValue::Bool(!self.is_truthy()))
685    }
686
687    fn rounded(&self, mode: Rounding, name: &str) -> Result<LogosValue, String> {
688        use LogosValue::*;
689        let recurse = |x: LogosValue| x.rounded(mode, name);
690        if let Some(r) = tower::integer_part(self, mode, &recurse) {
691            return r;
692        }
693        let whole = |f: f64| match mode {
694            Rounding::Floor => f.floor(),
695            Rounding::Ceil => f.ceil(),
696            Rounding::Nearest => f.round(),
697        };
698        let exact = |r: Ratio| match mode {
699            Rounding::Floor => r.floor(),
700            Rounding::Ceil => r.ceil(),
701            Rounding::Nearest => r.round(),
702        };
703        match self {
704            Float(f) => Ok(Int(whole(*f) as i64)),
705            Int(_) | BigInt(_) => Ok(self.clone()),
706            Rational(r) => Ok(LogosValue::from_bigint(exact((**r).clone()))),
707            Decimal(d) => Ok(LogosValue::from_bigint(exact(d.to_rational()))),
708            _ => Err(format!("{name}() requires a number, got {}", self.type_name())),
709        }
710    }
711
712    /// `a & b`: bitwise on integers, logical on booleans, and a non-negative big integer under a low
713    /// mask `2^k - 1` leaves its low `k` bits.
714    pub fn bit_and(&self, o: &LogosValue) -> Result<LogosValue, String> {
715        use LogosValue::*;
716        match (self, o) {
717            (Int(a), Int(b)) => Ok(Int(a & b)),
718            (BigInt(big), Int(m)) | (Int(m), BigInt(big))
719                if *m >= 0 && (*m as u64).wrapping_add(1).is_power_of_two() && !big.is_negative() =>
720            {
721                let modulus = Integer::from_i64(*m).add(&Integer::from_i64(1));
722                Ok(match big.div_rem(&modulus) {
723                    Some((_, r)) => LogosValue::from_bigint(r),
724                    None => Int(0),
725                })
726            }
727            (Bool(a), Bool(b)) => Ok(Bool(a & b)),
728            _ => Err(crate::failure::BITAND_OPERANDS.to_string()),
729        }
730    }
731
732    /// `a | b`.
733    pub fn bit_or(&self, o: &LogosValue) -> Result<LogosValue, String> {
734        use LogosValue::*;
735        match (self, o) {
736            (Int(a), Int(b)) => Ok(Int(a | b)),
737            (Bool(a), Bool(b)) => Ok(Bool(a | b)),
738            _ => Err(crate::failure::BITOR_OPERANDS.to_string()),
739        }
740    }
741
742    /// `a ^ b`.
743    pub fn bit_xor(&self, o: &LogosValue) -> Result<LogosValue, String> {
744        use LogosValue::*;
745        match (self, o) {
746            (Int(a), Int(b)) => Ok(Int(a ^ b)),
747            (Bool(a), Bool(b)) => Ok(Bool(a ^ b)),
748            _ => Err(crate::failure::BITXOR_OPERANDS.to_string()),
749        }
750    }
751
752    /// `a << b`, the count taken modulo the width.
753    pub fn shl(&self, o: &LogosValue) -> Result<LogosValue, String> {
754        match (self, o) {
755            (LogosValue::Int(a), LogosValue::Int(b)) => Ok(LogosValue::Int(a.wrapping_shl(*b as u32))),
756            _ => Err(crate::failure::SHL_OPERANDS.to_string()),
757        }
758    }
759
760    /// `a >> b`, the count taken modulo the width.
761    pub fn shr(&self, o: &LogosValue) -> Result<LogosValue, String> {
762        match (self, o) {
763            (LogosValue::Int(a), LogosValue::Int(b)) => Ok(LogosValue::Int(a.wrapping_shr(*b as u32))),
764            _ => Err(crate::failure::SHR_OPERANDS.to_string()),
765        }
766    }
767
768    /// `a is approximately b`, on the two values as floats.
769    pub fn approx_eq(&self, o: &LogosValue) -> Result<LogosValue, String> {
770        use LogosValue::*;
771        let as_f64 = |v: &LogosValue| match v {
772            Float(f) => Some(*f),
773            Int(n) => Some(*n as f64),
774            BigInt(b) => Some(b.to_f64()),
775            Rational(r) => Some(r.to_f64()),
776            _ => None,
777        };
778        match (as_f64(self), as_f64(o)) {
779            (Some(a), Some(b)) => Ok(Bool(crate::ops::logos_approx_eq(a, b))),
780            _ => Err(format!(
781                "`is approximately` compares numbers, got {} and {}",
782                self.type_name(),
783                o.type_name()
784            )),
785        }
786    }
787
788    /// `a followed by b`: the items of two sequences, in order.
789    pub fn seq_concat(&self, o: &LogosValue) -> Result<LogosValue, String> {
790        match (self, o) {
791            (LogosValue::List(a), LogosValue::List(b)) => {
792                Ok(LogosValue::list(a.iter().chain(b.iter()).cloned().collect()))
793            }
794            _ => Err("`followed by` requires two sequences (merge two sequences into one)".to_string()),
795        }
796    }
797
798    /// The builtin `abs`: exact on integers (promoting `|i64::MIN|`), rationals and decimals.
799    pub fn abs(&self) -> Result<LogosValue, String> {
800        use LogosValue::*;
801        match self {
802            Int(n) => Ok(match n.checked_abs() {
803                Some(a) => Int(a),
804                None => LogosValue::from_bigint(Integer::from_i64(*n).abs()),
805            }),
806            BigInt(b) => Ok(LogosValue::from_bigint(b.abs())),
807            Rational(r) => Ok(LogosValue::from_rational(r.abs())),
808            Decimal(d) => Ok(Decimal(Arc::new(d.abs()))),
809            Float(f) => Ok(Float(f.abs())),
810            _ => Err(format!("abs() requires a number, got {}", self.type_name())),
811        }
812    }
813
814    /// The builtin `sqrt`, a float.
815    pub fn sqrt(&self) -> Result<LogosValue, String> {
816        use LogosValue::*;
817        match self {
818            Float(f) => Ok(Float(f.sqrt())),
819            Int(n) => Ok(Float((*n as f64).sqrt())),
820            BigInt(b) => Ok(Float(b.to_f64().sqrt())),
821            _ => Err(format!("sqrt() requires a number, got {}", self.type_name())),
822        }
823    }
824
825    /// The builtin `min`.
826    pub fn min(&self, o: &LogosValue) -> Result<LogosValue, String> {
827        use LogosValue::*;
828        match (self, o) {
829            (Int(x), Int(y)) => Ok(Int(*x.min(y))),
830            (Float(x), Float(y)) => Ok(Float(float_min(*x, *y))),
831            (Int(x), Float(y)) => Ok(Float(float_min(*x as f64, *y))),
832            (Float(x), Int(y)) => Ok(Float(float_min(*x, *y as f64))),
833            (Decimal(x), Decimal(y)) => Ok(Decimal(if x <= y { x.clone() } else { y.clone() })),
834            _ => Err("min() requires numbers".to_string()),
835        }
836    }
837
838    /// The builtin `max`.
839    pub fn max(&self, o: &LogosValue) -> Result<LogosValue, String> {
840        use LogosValue::*;
841        match (self, o) {
842            (Int(x), Int(y)) => Ok(Int(*x.max(y))),
843            (Float(x), Float(y)) => Ok(Float(float_max(*x, *y))),
844            (Int(x), Float(y)) => Ok(Float(float_max(*x as f64, *y))),
845            (Float(x), Int(y)) => Ok(Float(float_max(*x, *y as f64))),
846            (Decimal(x), Decimal(y)) => Ok(Decimal(if x >= y { x.clone() } else { y.clone() })),
847            _ => Err("max() requires numbers".to_string()),
848        }
849    }
850
851    /// The builtin `pow`: an integer power is exact, a negative one a float.
852    pub fn power(&self, o: &LogosValue) -> Result<LogosValue, String> {
853        use LogosValue::*;
854        match (self, o) {
855            (Int(b), Int(e)) => Ok(if *e >= 0 {
856                match b.checked_pow(*e as u32) {
857                    Some(p) => Int(p),
858                    None => LogosValue::from_bigint(Integer::from_i64(*b).pow(*e as u32)),
859                }
860            } else {
861                Float((*b as f64).powi(*e as i32))
862            }),
863            (BigInt(b), Int(e)) => Ok(if *e >= 0 {
864                LogosValue::from_bigint(b.pow(*e as u32))
865            } else {
866                Float(b.to_f64().powi(*e as i32))
867            }),
868            (Float(b), Int(e)) => Ok(Float(b.powi(*e as i32))),
869            (Float(b), Float(e)) => Ok(Float(b.powf(*e))),
870            (Int(b), Float(e)) => Ok(Float((*b as f64).powf(*e))),
871            _ => Err("pow() requires numbers".to_string()),
872        }
873    }
874
875    /// `length of self`: a list's or a tuple's item count, a text's byte count.
876    pub fn length_of(&self) -> Result<i64, String> {
877        match self {
878            LogosValue::List(items) | LogosValue::Tuple(items) => Ok(items.len() as i64),
879            LogosValue::Text(t) => Ok(t.len() as i64),
880            _ => Err(format!("Cannot get length of {}", self.type_name())),
881        }
882    }
883
884    /// `self contains value`: an equal item of a list, a substring of a text.
885    pub fn contains_value(&self, value: &LogosValue) -> Result<bool, String> {
886        match self {
887            LogosValue::List(items) => Ok(items.iter().any(|i| i.values_equal(value))),
888            LogosValue::Text(t) => match value {
889                LogosValue::Text(needle) => Ok(t.contains(&**needle)),
890                other => Err(format!("Cannot check if Text contains {}", other.type_name())),
891            },
892            _ => Err(format!("Cannot check contains on {}", self.type_name())),
893        }
894    }
895
896    /// The values a `Repeat` over `self` binds, taken once before the loop runs: a list's items, a
897    /// text's characters.
898    pub fn items(&self) -> Result<Vec<LogosValue>, String> {
899        match self {
900            LogosValue::List(items) => Ok(items.to_vec()),
901            LogosValue::Text(t) => Ok(t.chars().map(|c| LogosValue::text(&c.to_string())).collect()),
902            _ => Err(format!("Cannot iterate over {}", self.type_name())),
903        }
904    }
905
906    /// `Push value to self`.
907    pub fn push_value(&mut self, value: LogosValue) -> Result<(), String> {
908        match self {
909            LogosValue::List(items) => {
910                Arc::make_mut(items).push(value);
911                Ok(())
912            }
913            _ => Err("Can only push to a List".to_string()),
914        }
915    }
916
917    /// `Set item index of self to value`.
918    pub fn set_item(&mut self, index: &LogosValue, value: LogosValue) -> Result<(), String> {
919        match (&mut *self, index) {
920            (LogosValue::List(items), LogosValue::Int(i)) => {
921                let at = crate::indexing::logos_offset(*i, items.len()).ok_or_else(|| index_out_of_bounds(i))?;
922                Arc::make_mut(items)[at] = value;
923                Ok(())
924            }
925            (LogosValue::List(_), _) => Err("List index must be an integer".to_string()),
926            _ => Err(format!("Cannot index into {}", self.type_name())),
927        }
928    }
929
930    /// `Pop from self`: the last item, or nothing from an empty list.
931    pub fn pop_value(&mut self) -> Result<LogosValue, String> {
932        match self {
933            LogosValue::List(items) => Ok(Arc::make_mut(items).pop().unwrap_or(LogosValue::Nothing)),
934            _ => Err("Can only pop from a List".to_string()),
935        }
936    }
937
938    /// `item index of self`: the 1-based item of a list or a tuple, the character of a text.
939    pub fn item(&self, index: &LogosValue) -> Result<LogosValue, String> {
940        use LogosValue::*;
941        match (self, index) {
942            (List(items) | Tuple(items), Int(i)) => crate::indexing::logos_offset(*i, items.len())
943                .map(|at| items[at].clone())
944                .ok_or_else(|| index_out_of_bounds(i)),
945            (Text(t), Int(i)) => {
946                let chars = t.chars().count();
947                crate::indexing::logos_offset(*i, chars)
948                    .map(|at| LogosValue::text(&t.chars().nth(at).expect("offset in range").to_string()))
949                    .ok_or_else(|| index_out_of_bounds(i))
950            }
951            _ => Err(format!("Cannot index {} with {}", self.type_name(), index.type_name())),
952        }
953    }
954
955    /// `items start through end of self`: the 1-based, inclusive run of a list's items ([`crate::logos_slice_range`]);
956    /// one that reaches outside the list is empty.
957    pub fn slice(&self, start: &LogosValue, end: &LogosValue) -> Result<LogosValue, String> {
958        match (self, start, end) {
959            (LogosValue::List(items), LogosValue::Int(s), LogosValue::Int(e)) => {
960                Ok(LogosValue::list(items[crate::logos_slice_range(*s, *e, items.len())].to_vec()))
961            }
962            _ => Err("Slice requires List and Int indices".to_string()),
963        }
964    }
965
966    /// The machine integer this is where the language takes one: refused with `past_word` for an integer past
967    /// `i64`, with `fraction` for a rational that is not whole, and by its type for any other value.
968    pub fn integer_at(&self, past_word: &str, fraction: &str) -> Result<i64, String> {
969        match self {
970            LogosValue::Int(n) => Ok(*n),
971            LogosValue::BigInt(_) => Err(past_word.to_string()),
972            LogosValue::Rational(_) => Err(fraction.to_string()),
973            other => Err(format!("Expected Int, found {}", other.type_name())),
974        }
975    }
976
977    /// The real an operator over a real answers.
978    pub fn into_real(self) -> f64 {
979        match self {
980            LogosValue::Float(f) => f,
981            other => unreachable!("an operator over a real answered a {}", other.type_name()),
982        }
983    }
984
985    /// The language's `floor`.
986    pub fn floor(&self) -> Result<LogosValue, String> {
987        self.rounded(Rounding::Floor, "floor")
988    }
989
990    /// The language's `ceil`.
991    pub fn ceil(&self) -> Result<LogosValue, String> {
992        self.rounded(Rounding::Ceil, "ceil")
993    }
994
995    /// The language's `round`.
996    pub fn round(&self) -> Result<LogosValue, String> {
997        self.rounded(Rounding::Nearest, "round")
998    }
999}
1000
1001impl fmt::Display for LogosValue {
1002    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1003        f.write_str(&self.display_string())
1004    }
1005}
1006
1007/// An unset slot of an exact type, as the interpreter starts one: nothing.
1008impl Default for LogosValue {
1009    fn default() -> Self {
1010        LogosValue::Nothing
1011    }
1012}
1013
1014impl PartialEq for LogosValue {
1015    fn eq(&self, o: &Self) -> bool {
1016        self.values_equal(o)
1017    }
1018}
1019
1020impl From<i64> for LogosValue {
1021    fn from(n: i64) -> Self {
1022        LogosValue::Int(n)
1023    }
1024}
1025
1026impl From<f64> for LogosValue {
1027    fn from(f: f64) -> Self {
1028        LogosValue::Float(f)
1029    }
1030}
1031
1032impl From<bool> for LogosValue {
1033    fn from(b: bool) -> Self {
1034        LogosValue::Bool(b)
1035    }
1036}
1037
1038impl From<&str> for LogosValue {
1039    fn from(t: &str) -> Self {
1040        LogosValue::text(t)
1041    }
1042}
1043
1044impl From<String> for LogosValue {
1045    fn from(t: String) -> Self {
1046        LogosValue::text(&t)
1047    }
1048}
1049
1050impl From<crate::types::LogosRational> for LogosValue {
1051    fn from(r: crate::types::LogosRational) -> Self {
1052        LogosValue::from_rational(r.0)
1053    }
1054}
1055
1056impl From<crate::types::LogosInt> for LogosValue {
1057    fn from(n: crate::types::LogosInt) -> Self {
1058        match n {
1059            crate::types::LogosInt::Small(n) => LogosValue::Int(n),
1060            crate::types::LogosInt::Big(b) => LogosValue::from_bigint(*b),
1061        }
1062    }
1063}
1064
1065impl<T: Into<LogosValue>> From<Vec<T>> for LogosValue {
1066    fn from(items: Vec<T>) -> Self {
1067        LogosValue::list(items.into_iter().map(Into::into).collect())
1068    }
1069}
1070
1071macro_rules! from_machine_integer {
1072    ($($t:ty),*) => {$(
1073        impl From<$t> for LogosValue {
1074            fn from(n: $t) -> Self {
1075                match i64::try_from(n) {
1076                    Ok(n) => LogosValue::Int(n),
1077                    Err(_) => LogosValue::from_bigint(
1078                        BigInt::parse_decimal(&n.to_string()).expect("a machine integer's digits"),
1079                    ),
1080                }
1081            }
1082        }
1083    )*};
1084}
1085
1086from_machine_integer!(i8, i16, i32, i128, u8, u16, u32, u64, u128, usize);
1087
1088impl From<()> for LogosValue {
1089    fn from(_: ()) -> Self {
1090        LogosValue::Nothing
1091    }
1092}
1093
1094impl From<crate::types::LogosDecimal> for LogosValue {
1095    fn from(d: crate::types::LogosDecimal) -> Self {
1096        LogosValue::Decimal(Arc::new(d.0))
1097    }
1098}
1099
1100impl<T: Clone + Into<LogosValue>> From<crate::types::LogosSeq<T>> for LogosValue {
1101    fn from(items: crate::types::LogosSeq<T>) -> Self {
1102        LogosValue::list(items.0.borrow().iter().cloned().map(Into::into).collect())
1103    }
1104}
1105
1106impl crate::ops::Truthy for LogosValue {
1107    fn truthy(&self) -> bool {
1108        answered(self.decided_truth())
1109    }
1110}
1111
1112impl crate::indexing::LogosIndex<i64> for LogosValue {
1113    type Output = LogosValue;
1114    fn logos_get(&self, index: i64) -> LogosValue {
1115        answered(self.item(&LogosValue::Int(index)))
1116    }
1117}
1118
1119impl crate::indexing::LogosIndex<LogosValue> for LogosValue {
1120    type Output = LogosValue;
1121    fn logos_get(&self, index: LogosValue) -> LogosValue {
1122        answered(self.item(&index))
1123    }
1124}
1125
1126impl TowerValue for LogosValue {
1127    fn exact(&self) -> Option<ExactRef<'_, Self>> {
1128        Some(match self {
1129            LogosValue::Algebraic(a) => ExactRef::Algebraic(a),
1130            LogosValue::ExactReal(x) => ExactRef::Real(x),
1131            LogosValue::Hyperreal(h) => ExactRef::Hyper(h),
1132            LogosValue::Hypernatural(n) => ExactRef::Natural(n),
1133            LogosValue::Ordinal(o) => ExactRef::Ordinal(o),
1134            LogosValue::Depends(d) => ExactRef::Depends(d),
1135            LogosValue::Converging(c) => ExactRef::Converging(c),
1136            _ => return None,
1137        })
1138    }
1139
1140    fn standard_rational(&self) -> Option<Rational> {
1141        match self {
1142            LogosValue::Float(f) => rational_from_f64_exact(*f),
1143            other => other.rat(),
1144        }
1145    }
1146
1147    fn integer(&self) -> Option<BigInt> {
1148        self.big()
1149    }
1150
1151    fn exact_rational(&self) -> Option<Rational> {
1152        match self {
1153            LogosValue::Int(n) => Some(Rational::from_i64(*n)),
1154            LogosValue::BigInt(b) => Some(Rational::from_bigint((**b).clone())),
1155            LogosValue::Rational(r) => Some((**r).clone()),
1156            _ => None,
1157        }
1158    }
1159
1160    fn is_standard_number(&self) -> bool {
1161        matches!(
1162            self,
1163            LogosValue::Int(_)
1164                | LogosValue::BigInt(_)
1165                | LogosValue::Rational(_)
1166                | LogosValue::Decimal(_)
1167                | LogosValue::Float(_)
1168        )
1169    }
1170
1171    fn text(&self) -> Option<&str> {
1172        match self {
1173            LogosValue::Text(t) => Some(t),
1174            _ => None,
1175        }
1176    }
1177
1178    fn type_name(&self) -> String {
1179        LogosValue::type_name(self).to_string()
1180    }
1181
1182    fn display_string(&self) -> String {
1183        LogosValue::display_string(self)
1184    }
1185
1186    fn values_equal(&self, other: &Self) -> bool {
1187        LogosValue::values_equal(self, other)
1188    }
1189
1190    fn is_nothing(&self) -> bool {
1191        matches!(self, LogosValue::Nothing)
1192    }
1193
1194    fn from_rational(r: Rational) -> Self {
1195        LogosValue::from_rational(r)
1196    }
1197
1198    fn from_bigint(b: BigInt) -> Self {
1199        LogosValue::from_bigint(b)
1200    }
1201
1202    fn boolean(b: bool) -> Self {
1203        LogosValue::Bool(b)
1204    }
1205
1206    fn nothing() -> Self {
1207        LogosValue::Nothing
1208    }
1209
1210    fn algebraic(a: Algebraic) -> Self {
1211        LogosValue::Algebraic(Arc::new(a))
1212    }
1213
1214    fn exact_real(x: ExactReal) -> Self {
1215        LogosValue::ExactReal(Arc::new(x))
1216    }
1217
1218    fn hyper(h: HyperValue) -> Self {
1219        LogosValue::Hyperreal(Arc::new(h))
1220    }
1221
1222    fn natural(n: NaturalValue) -> Self {
1223        LogosValue::Hypernatural(Arc::new(n))
1224    }
1225
1226    fn ordinal(o: Ordinal) -> Self {
1227        LogosValue::Ordinal(Arc::new(o))
1228    }
1229
1230    fn depends(d: DependsValue<Self>) -> Self {
1231        LogosValue::Depends(Arc::new(d))
1232    }
1233
1234    fn converging(c: Converging<Self>) -> Self {
1235        LogosValue::Converging(Arc::new(c))
1236    }
1237}
1238
1239impl ValueAlgebra for LogosValue {
1240    fn add(a: Self, b: Self) -> Result<Self, String> {
1241        a.add(&b)
1242    }
1243
1244    fn subtract(a: Self, b: Self) -> Result<Self, String> {
1245        a.sub(&b)
1246    }
1247
1248    fn multiply(a: Self, b: Self) -> Result<Self, String> {
1249        a.mul(&b)
1250    }
1251
1252    fn exact_divide(a: Self, b: Self) -> Result<Self, String> {
1253        a.exact_div(&b)
1254    }
1255
1256    fn modulo(a: Self, b: Self) -> Result<Self, String> {
1257        a.rem(&b)
1258    }
1259
1260    fn power(a: Self, b: Self) -> Result<Self, String> {
1261        a.pow(&b)
1262    }
1263
1264    fn holds(rel: Rel, a: &Self, b: &Self) -> Result<bool, String> {
1265        a.relation(rel, b)?.decided_truth()
1266    }
1267
1268    fn floor(v: Self) -> Result<Self, String> {
1269        LogosValue::floor(&v)
1270    }
1271
1272    fn ceil(v: Self) -> Result<Self, String> {
1273        LogosValue::ceil(&v)
1274    }
1275
1276    fn list(values: Vec<Self>) -> Self {
1277        LogosValue::list(values)
1278    }
1279
1280    fn shape(&self) -> Shape<Self> {
1281        match self {
1282            LogosValue::Bool(_) => Shape::Bool,
1283            LogosValue::Int(n) => Shape::Int(*n),
1284            LogosValue::Float(_) => Shape::Float,
1285            LogosValue::BigInt(b) => Shape::BigInt((**b).clone()),
1286            LogosValue::Rational(r) => Shape::Rational((**r).clone()),
1287            LogosValue::Decimal(_) => Shape::Decimal,
1288            LogosValue::Text(t) => Shape::Text(t.len()),
1289            LogosValue::List(items) => Shape::List(items.to_vec()),
1290            LogosValue::Tuple(items) => Shape::Tuple(items.to_vec()),
1291            _ => Shape::Other,
1292        }
1293    }
1294}
1295
1296// ── real numbers a compiled program defines ───────────────────────────────────────────────────
1297
1298/// A function a compiled program defines a real number by: its answer at a place, or its refusal.
1299/// The function reads nothing but its argument, so any thread may call it.
1300type Definer = Arc<dyn Fn(i64) -> Result<LogosValue, String> + Send + Sync>;
1301
1302/// The rational a compiled function's answer is; anything else is refused in a defined real's words.
1303pub(crate) fn answered_rational(name: &str, n: u64, v: &LogosValue) -> Result<Rational, String> {
1304    match v {
1305        LogosValue::Int(i) => Ok(Rational::from_i64(*i)),
1306        LogosValue::BigInt(b) => Ok(Rational::from_bigint((**b).clone())),
1307        LogosValue::Rational(r) => Ok((**r).clone()),
1308        other => Err(logicaffeine_base::exact_real::not_a_rational_answer(name, n, other.type_name())),
1309    }
1310}
1311
1312/// A compiled function a real number is defined by, and how the program spells it.
1313struct Compiled {
1314    name: String,
1315    f: Definer,
1316}
1317
1318impl logicaffeine_base::exact_real::Approximant for Compiled {
1319    fn call(&self, n: u64) -> Result<Rational, String> {
1320        let arg = i64::try_from(n).map_err(|_| format!("{}({n}) is past every Int", self.name))?;
1321        answered_rational(&self.name, n, &(self.f)(arg)?)
1322    }
1323}
1324
1325impl LogosValue {
1326    /// The real number `f` defines by its digits in `base` or its approximations (`kind`, as
1327    /// [`logicaffeine_base::exact_real::Definition::named`] reads it), `name` being how the program
1328    /// spells `f`.
1329    pub fn defined_real(
1330        kind: &str,
1331        base: i64,
1332        name: &str,
1333        f: impl Fn(i64) -> LogosValue + Send + Sync + 'static,
1334    ) -> LogosValue {
1335        answered(Self::define_real(kind, base, name, move |n| Ok(f(n))))
1336    }
1337
1338    /// [`LogosValue::defined_real`] for a function that may refuse an answer, refused itself when
1339    /// `kind` and `base` name no definition.
1340    pub fn define_real(
1341        kind: &str,
1342        base: i64,
1343        name: &str,
1344        f: impl Fn(i64) -> Result<LogosValue, String> + Send + Sync + 'static,
1345    ) -> Result<LogosValue, String> {
1346        let definition = logicaffeine_base::exact_real::Definition::named(kind, base)?;
1347        let source = Arc::new(Compiled {
1348            name: name.to_string(),
1349            f: Arc::new(f),
1350        });
1351        Ok(LogosValue::ExactReal(Arc::new(ExactReal::defined(definition, name, source))))
1352    }
1353
1354    /// `Ok` when the value may cross to a task, `Err` with the interpreter's sentence when it holds a real
1355    /// number a function of the program defines, which stays with the program.
1356    pub fn sendable(&self) -> Result<(), String> {
1357        match self {
1358            LogosValue::List(items) | LogosValue::Tuple(items) => items.iter().try_for_each(LogosValue::sendable),
1359            v if logicaffeine_base::tower::transmissible(v) => Ok(()),
1360            _ => Err(logicaffeine_base::exact_real::not_sendable()),
1361        }
1362    }
1363}
1364
1365#[cfg(test)]
1366#[path = "../../logicaffeine_tests/unit/logicaffeine_data/exact/tests.rs"]
1367mod tests;