1use oxilean_kernel::{
6 BinderInfo, Declaration, Environment, Expr, InductiveEnv, InductiveType, IntroRule, Level, Name,
7};
8
9use super::functions::*;
10
11#[derive(Clone, Debug, Default)]
13pub struct SumStats {
14 pub left_count: usize,
16 pub right_count: usize,
18}
19impl SumStats {
20 pub fn from_slice<A, B>(xs: &[Coproduct<A, B>]) -> Self {
22 let left_count = xs.iter().filter(|c| c.is_left()).count();
23 let right_count = xs.len() - left_count;
24 Self {
25 left_count,
26 right_count,
27 }
28 }
29 pub fn total(&self) -> usize {
31 self.left_count + self.right_count
32 }
33 pub fn left_fraction(&self) -> f64 {
35 if self.total() == 0 {
36 0.0
37 } else {
38 self.left_count as f64 / self.total() as f64
39 }
40 }
41 pub fn all_left(&self) -> bool {
43 self.right_count == 0 && self.total() > 0
44 }
45 pub fn all_right(&self) -> bool {
47 self.left_count == 0 && self.total() > 0
48 }
49}
50pub struct SumChain<A, B> {
52 inner: Coproduct<A, B>,
53}
54impl<A, B> SumChain<A, B> {
55 pub fn new(c: Coproduct<A, B>) -> Self {
57 Self { inner: c }
58 }
59 pub fn map<C>(self, f: impl FnOnce(B) -> C) -> SumChain<A, C> {
61 SumChain {
62 inner: self.inner.map_right(f),
63 }
64 }
65 pub fn flat_map<C>(self, f: impl FnOnce(B) -> Coproduct<A, C>) -> SumChain<A, C> {
67 SumChain {
68 inner: match self.inner {
69 Coproduct::Inl(a) => Coproduct::Inl(a),
70 Coproduct::Inr(b) => f(b),
71 },
72 }
73 }
74 pub fn into_inner(self) -> Coproduct<A, B> {
76 self.inner
77 }
78 pub fn is_ok(&self) -> bool {
80 self.inner.is_right()
81 }
82 pub fn is_err(&self) -> bool {
84 self.inner.is_left()
85 }
86}
87#[allow(dead_code)]
89pub struct SumBifunctor<A, B, C, D> {
90 _a: std::marker::PhantomData<A>,
92 _b: std::marker::PhantomData<B>,
94 _c: std::marker::PhantomData<C>,
96 _d: std::marker::PhantomData<D>,
98 pub name: String,
100}
101impl<A, B, C, D> SumBifunctor<A, B, C, D> {
102 pub fn new(name: impl Into<String>) -> Self {
104 SumBifunctor {
105 _a: std::marker::PhantomData,
106 _b: std::marker::PhantomData,
107 _c: std::marker::PhantomData,
108 _d: std::marker::PhantomData,
109 name: name.into(),
110 }
111 }
112 pub fn apply(
114 &self,
115 s: Coproduct<A, B>,
116 f: impl FnOnce(A) -> C,
117 g: impl FnOnce(B) -> D,
118 ) -> Coproduct<C, D> {
119 s.bimap(f, g)
120 }
121}
122#[derive(Debug, Clone, PartialEq, Eq, Hash)]
125pub enum Coproduct<A, B> {
126 Inl(A),
128 Inr(B),
130}
131impl<A, B> Coproduct<A, B> {
132 pub fn inl(a: A) -> Self {
134 Coproduct::Inl(a)
135 }
136 pub fn inr(b: B) -> Self {
138 Coproduct::Inr(b)
139 }
140 pub fn is_left(&self) -> bool {
142 matches!(self, Coproduct::Inl(_))
143 }
144 pub fn is_right(&self) -> bool {
146 matches!(self, Coproduct::Inr(_))
147 }
148 pub fn elim<C>(self, f: impl FnOnce(A) -> C, g: impl FnOnce(B) -> C) -> C {
150 match self {
151 Coproduct::Inl(a) => f(a),
152 Coproduct::Inr(b) => g(b),
153 }
154 }
155 pub fn swap(self) -> Coproduct<B, A> {
157 match self {
158 Coproduct::Inl(a) => Coproduct::Inr(a),
159 Coproduct::Inr(b) => Coproduct::Inl(b),
160 }
161 }
162 pub fn bimap<C, D>(self, f: impl FnOnce(A) -> C, g: impl FnOnce(B) -> D) -> Coproduct<C, D> {
164 match self {
165 Coproduct::Inl(a) => Coproduct::Inl(f(a)),
166 Coproduct::Inr(b) => Coproduct::Inr(g(b)),
167 }
168 }
169 pub fn map_left<C>(self, f: impl FnOnce(A) -> C) -> Coproduct<C, B> {
171 match self {
172 Coproduct::Inl(a) => Coproduct::Inl(f(a)),
173 Coproduct::Inr(b) => Coproduct::Inr(b),
174 }
175 }
176 pub fn map_right<D>(self, g: impl FnOnce(B) -> D) -> Coproduct<A, D> {
178 match self {
179 Coproduct::Inl(a) => Coproduct::Inl(a),
180 Coproduct::Inr(b) => Coproduct::Inr(g(b)),
181 }
182 }
183 pub fn left_or(self, default: A) -> A {
185 match self {
186 Coproduct::Inl(a) => a,
187 Coproduct::Inr(_) => default,
188 }
189 }
190 pub fn right_or(self, default: B) -> B {
192 match self {
193 Coproduct::Inl(_) => default,
194 Coproduct::Inr(b) => b,
195 }
196 }
197 pub fn into_left(self) -> Option<A> {
199 match self {
200 Coproduct::Inl(a) => Some(a),
201 Coproduct::Inr(_) => None,
202 }
203 }
204 pub fn into_right(self) -> Option<B> {
206 match self {
207 Coproduct::Inl(_) => None,
208 Coproduct::Inr(b) => Some(b),
209 }
210 }
211 pub fn into_result(self) -> Result<B, A> {
213 match self {
214 Coproduct::Inl(a) => Err(a),
215 Coproduct::Inr(b) => Ok(b),
216 }
217 }
218 pub fn from_result(r: Result<B, A>) -> Self {
220 match r {
221 Ok(b) => Coproduct::Inr(b),
222 Err(a) => Coproduct::Inl(a),
223 }
224 }
225}
226impl<A: Clone, B: Clone> Coproduct<A, B> {
227 pub fn merge(self) -> A
229 where
230 A: Clone,
231 B: Into<A>,
232 {
233 match self {
234 Coproduct::Inl(a) => a,
235 Coproduct::Inr(b) => b.into(),
236 }
237 }
238}
239#[derive(Debug, Clone, PartialEq, Eq)]
241pub enum Sum4<A, B, C, D> {
242 In1(A),
244 In2(B),
246 In3(C),
248 In4(D),
250}
251impl<A, B, C, D> Sum4<A, B, C, D> {
252 #[allow(clippy::too_many_arguments)]
254 pub fn elim<E>(
255 self,
256 f1: impl FnOnce(A) -> E,
257 f2: impl FnOnce(B) -> E,
258 f3: impl FnOnce(C) -> E,
259 f4: impl FnOnce(D) -> E,
260 ) -> E {
261 match self {
262 Sum4::In1(a) => f1(a),
263 Sum4::In2(b) => f2(b),
264 Sum4::In3(c) => f3(c),
265 Sum4::In4(d) => f4(d),
266 }
267 }
268 pub fn tag(&self) -> u8 {
270 match self {
271 Sum4::In1(_) => 1,
272 Sum4::In2(_) => 2,
273 Sum4::In3(_) => 3,
274 Sum4::In4(_) => 4,
275 }
276 }
277 pub fn is_first(&self) -> bool {
279 matches!(self, Sum4::In1(_))
280 }
281 pub fn is_second(&self) -> bool {
283 matches!(self, Sum4::In2(_))
284 }
285 pub fn is_third(&self) -> bool {
287 matches!(self, Sum4::In3(_))
288 }
289 pub fn is_fourth(&self) -> bool {
291 matches!(self, Sum4::In4(_))
292 }
293}
294#[derive(Clone, Debug, Default)]
296pub struct InjectionMap {
297 labels: Vec<(u8, String)>,
298}
299impl InjectionMap {
300 pub fn new() -> Self {
302 Self::default()
303 }
304 pub fn register(&mut self, tag: u8, label: impl Into<String>) {
306 self.labels.push((tag, label.into()));
307 }
308 pub fn get(&self, tag: u8) -> Option<&str> {
310 self.labels
311 .iter()
312 .find(|(t, _)| *t == tag)
313 .map(|(_, l)| l.as_str())
314 }
315 pub fn len(&self) -> usize {
317 self.labels.len()
318 }
319 pub fn is_empty(&self) -> bool {
321 self.labels.is_empty()
322 }
323}
324#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct Tagged<T, A> {
327 pub tag: T,
329 pub value: A,
331}
332impl<T, A> Tagged<T, A> {
333 pub fn new(tag: T, value: A) -> Self {
335 Tagged { tag, value }
336 }
337 pub fn map<B>(self, f: impl FnOnce(A) -> B) -> Tagged<T, B> {
339 Tagged {
340 tag: self.tag,
341 value: f(self.value),
342 }
343 }
344 pub fn map_tag<U>(self, f: impl FnOnce(T) -> U) -> Tagged<U, A> {
346 Tagged {
347 tag: f(self.tag),
348 value: self.value,
349 }
350 }
351}
352#[allow(dead_code)]
354pub struct TaggedUnionSm {
355 pub tag: String,
357 pub payload: String,
359}
360impl TaggedUnionSm {
361 pub fn new(tag: impl Into<String>, payload: impl Into<String>) -> Self {
363 TaggedUnionSm {
364 tag: tag.into(),
365 payload: payload.into(),
366 }
367 }
368 pub fn render(&self) -> String {
370 format!("{}({})", self.tag, self.payload)
371 }
372 pub fn has_tag(&self, t: &str) -> bool {
374 self.tag == t
375 }
376}
377#[derive(Debug, Clone, PartialEq, Eq)]
379pub struct Pair<A, B> {
380 pub fst: A,
382 pub snd: B,
384}
385impl<A, B> Pair<A, B> {
386 pub fn new(fst: A, snd: B) -> Self {
388 Pair { fst, snd }
389 }
390 pub fn swap(self) -> Pair<B, A> {
392 Pair {
393 fst: self.snd,
394 snd: self.fst,
395 }
396 }
397 pub fn map_fst<C>(self, f: impl FnOnce(A) -> C) -> Pair<C, B> {
399 Pair {
400 fst: f(self.fst),
401 snd: self.snd,
402 }
403 }
404 pub fn map_snd<D>(self, g: impl FnOnce(B) -> D) -> Pair<A, D> {
406 Pair {
407 fst: self.fst,
408 snd: g(self.snd),
409 }
410 }
411 pub fn into_tuple(self) -> (A, B) {
413 (self.fst, self.snd)
414 }
415 pub fn from_tuple(t: (A, B)) -> Self {
417 Pair { fst: t.0, snd: t.1 }
418 }
419}
420#[allow(dead_code)]
422pub struct EitherPartitionSm<L, R> {
423 pub lefts: Vec<L>,
425 pub rights: Vec<R>,
427}
428impl<L, R> EitherPartitionSm<L, R> {
429 pub fn from_vec(xs: Vec<Coproduct<L, R>>) -> Self {
431 let (ls, rs) = partition(xs);
432 EitherPartitionSm {
433 lefts: ls,
434 rights: rs,
435 }
436 }
437 pub fn total(&self) -> usize {
439 self.lefts.len() + self.rights.len()
440 }
441 pub fn all_right(&self) -> bool {
443 self.lefts.is_empty()
444 }
445 pub fn all_left(&self) -> bool {
447 self.rights.is_empty()
448 }
449 pub fn left_count(&self) -> usize {
451 self.lefts.len()
452 }
453 pub fn right_count(&self) -> usize {
455 self.rights.len()
456 }
457}
458#[allow(dead_code)]
460pub struct SumTraversal<A, B> {
461 _a: std::marker::PhantomData<A>,
463 _b: std::marker::PhantomData<B>,
465 pub description: String,
467}
468impl<A, B> SumTraversal<A, B> {
469 pub fn new(description: impl Into<String>) -> Self {
471 SumTraversal {
472 _a: std::marker::PhantomData,
473 _b: std::marker::PhantomData,
474 description: description.into(),
475 }
476 }
477 pub fn traverse_option<C>(
479 &self,
480 s: Coproduct<A, B>,
481 f: impl FnOnce(B) -> Option<C>,
482 ) -> Option<Coproduct<A, C>> {
483 match s {
484 Coproduct::Inl(a) => Some(Coproduct::Inl(a)),
485 Coproduct::Inr(b) => f(b).map(Coproduct::Inr),
486 }
487 }
488}
489#[allow(dead_code)]
492pub struct SumUniversal<A, B, Z> {
493 pub left_branch: std::marker::PhantomData<fn(A) -> Z>,
495 pub right_branch: std::marker::PhantomData<fn(B) -> Z>,
497 pub description: String,
499}
500impl<A, B, Z> SumUniversal<A, B, Z> {
501 pub fn new(description: impl Into<String>) -> Self {
503 SumUniversal {
504 left_branch: std::marker::PhantomData,
505 right_branch: std::marker::PhantomData,
506 description: description.into(),
507 }
508 }
509 pub fn mediate(&self, s: Coproduct<A, B>, f: impl FnOnce(A) -> Z, g: impl FnOnce(B) -> Z) -> Z {
511 s.elim(f, g)
512 }
513}
514#[derive(Debug, Clone, PartialEq, Eq)]
516pub enum Sum3<A, B, C> {
517 In1(A),
519 In2(B),
521 In3(C),
523}
524impl<A, B, C> Sum3<A, B, C> {
525 pub fn elim<D>(
527 self,
528 f1: impl FnOnce(A) -> D,
529 f2: impl FnOnce(B) -> D,
530 f3: impl FnOnce(C) -> D,
531 ) -> D {
532 match self {
533 Sum3::In1(a) => f1(a),
534 Sum3::In2(b) => f2(b),
535 Sum3::In3(c) => f3(c),
536 }
537 }
538 pub fn is_first(&self) -> bool {
540 matches!(self, Sum3::In1(_))
541 }
542 pub fn is_second(&self) -> bool {
544 matches!(self, Sum3::In2(_))
545 }
546 pub fn is_third(&self) -> bool {
548 matches!(self, Sum3::In3(_))
549 }
550}