1use std::cell::OnceCell;
6
7use super::functions::*;
8use std::collections::HashMap;
9
10#[allow(dead_code)]
12#[derive(Debug, Clone)]
13pub struct ThunkApp<A: Clone> {
14 pub val: A,
15}
16#[allow(dead_code)]
17impl<A: Clone> ThunkApp<A> {
18 pub fn pure(a: A) -> Self {
19 ThunkApp { val: a }
20 }
21 pub fn map<B: Clone, F: Fn(A) -> B>(self, f: F) -> ThunkApp<B> {
22 ThunkApp { val: f(self.val) }
23 }
24 pub fn ap<B: Clone, F>(self, tf: ThunkApp<F>) -> ThunkApp<B>
25 where
26 F: Fn(A) -> B + Clone,
27 {
28 ThunkApp {
29 val: (tf.val)(self.val),
30 }
31 }
32}
33pub struct Memo<A: std::hash::Hash + Eq + Clone, B: Clone> {
37 f: Box<dyn Fn(&A) -> B>,
38 cache: std::collections::HashMap<A, B>,
39}
40impl<A: std::hash::Hash + Eq + Clone, B: Clone> Memo<A, B> {
41 pub fn new<F: Fn(&A) -> B + 'static>(f: F) -> Self {
43 Self {
44 f: Box::new(f),
45 cache: std::collections::HashMap::new(),
46 }
47 }
48 pub fn call(&mut self, arg: &A) -> &B {
50 if !self.cache.contains_key(arg) {
51 let result = (self.f)(arg);
52 self.cache.insert(arg.clone(), result);
53 }
54 &self.cache[arg]
55 }
56 pub fn clear_cache(&mut self) {
58 self.cache.clear();
59 }
60 pub fn cache_size(&self) -> usize {
62 self.cache.len()
63 }
64}
65pub enum ThunkTree<T> {
67 Leaf(T),
69 Node(Box<dyn Fn() -> Vec<ThunkTree<T>>>),
71}
72impl<T: Clone> ThunkTree<T> {
73 pub fn leaf(value: T) -> Self {
75 Self::Leaf(value)
76 }
77 pub fn node<F: Fn() -> Vec<ThunkTree<T>> + 'static>(f: F) -> Self {
79 Self::Node(Box::new(f))
80 }
81 pub fn leaves(&self) -> Vec<T>
83 where
84 T: Clone,
85 {
86 match self {
87 ThunkTree::Leaf(v) => vec![v.clone()],
88 ThunkTree::Node(f) => f().iter().flat_map(|c| c.leaves()).collect(),
89 }
90 }
91 pub fn is_leaf(&self) -> bool {
93 matches!(self, ThunkTree::Leaf(_))
94 }
95}
96pub struct LazyList<T> {
101 produced: Vec<T>,
102 next: Option<Box<dyn Fn(usize) -> Option<T>>>,
103}
104impl<T: Clone> LazyList<T> {
105 pub fn from_fn<F: Fn(usize) -> Option<T> + 'static>(f: F) -> Self {
107 Self {
108 produced: Vec::new(),
109 next: Some(Box::new(f)),
110 }
111 }
112 pub fn get(&mut self, i: usize) -> Option<&T> {
114 while self.produced.len() <= i {
115 let idx = self.produced.len();
116 if let Some(f) = &self.next {
117 match f(idx) {
118 Some(v) => self.produced.push(v),
119 None => {
120 self.next = None;
121 break;
122 }
123 }
124 } else {
125 break;
126 }
127 }
128 self.produced.get(i)
129 }
130 pub fn take(&mut self, n: usize) -> Vec<T> {
132 (0..n).filter_map(|i| self.get(i).cloned()).collect()
133 }
134 pub fn produced_count(&self) -> usize {
136 self.produced.len()
137 }
138}
139pub struct TryThunk<T, E> {
141 init: Option<Box<dyn FnOnce() -> Result<T, E>>>,
142 pub(super) value: Option<Result<T, E>>,
143}
144impl<T, E> TryThunk<T, E> {
145 pub fn new<F: FnOnce() -> Result<T, E> + 'static>(f: F) -> Self {
147 Self {
148 init: Some(Box::new(f)),
149 value: None,
150 }
151 }
152 pub fn force(&mut self) -> &Result<T, E> {
154 if self.value.is_none() {
155 if let Some(f) = self.init.take() {
156 self.value = Some(f());
157 }
158 }
159 self.value
160 .as_ref()
161 .expect("TryThunk: value missing after force")
162 }
163 pub fn is_forced(&self) -> bool {
165 self.value.is_some()
166 }
167}
168#[allow(dead_code)]
172pub enum LazyStream<T> {
173 Nil,
175 Cons(T, Box<dyn FnOnce() -> LazyStream<T>>),
177}
178#[allow(dead_code)]
179impl<T: Clone> LazyStream<T> {
180 pub fn nil() -> Self {
182 LazyStream::Nil
183 }
184 pub fn cons<F: FnOnce() -> LazyStream<T> + 'static>(head: T, tail: F) -> Self {
186 LazyStream::Cons(head, Box::new(tail))
187 }
188 pub fn take(self, n: usize) -> Vec<T> {
190 let mut result = Vec::new();
191 let mut current = self;
192 for _ in 0..n {
193 match current {
194 LazyStream::Nil => break,
195 LazyStream::Cons(h, tl) => {
196 result.push(h);
197 current = tl();
198 }
199 }
200 }
201 result
202 }
203 pub fn is_nil(&self) -> bool {
205 matches!(self, LazyStream::Nil)
206 }
207}
208pub struct ThunkSeq<T> {
212 items: Vec<Box<dyn Fn() -> T>>,
213 cache: Vec<Option<T>>,
214}
215impl<T: Clone> ThunkSeq<T> {
216 pub fn new() -> Self {
218 Self {
219 items: Vec::new(),
220 cache: Vec::new(),
221 }
222 }
223 pub fn push<F: Fn() -> T + 'static>(&mut self, f: F) {
225 self.items.push(Box::new(f));
226 self.cache.push(None);
227 }
228 pub fn get(&mut self, i: usize) -> Option<&T> {
230 if i >= self.items.len() {
231 return None;
232 }
233 if self.cache[i].is_none() {
234 self.cache[i] = Some((self.items[i])());
235 }
236 self.cache[i].as_ref()
237 }
238 pub fn len(&self) -> usize {
240 self.items.len()
241 }
242 pub fn is_empty(&self) -> bool {
244 self.items.is_empty()
245 }
246 pub fn forced_count(&self) -> usize {
248 self.cache.iter().filter(|c| c.is_some()).count()
249 }
250}
251pub struct OnceCellThunk<T> {
253 pub(super) cell: OnceCell<T>,
254 init: Option<Box<dyn FnOnce() -> T>>,
255}
256impl<T> OnceCellThunk<T> {
257 pub fn new<F: FnOnce() -> T + 'static>(f: F) -> Self {
259 Self {
260 cell: OnceCell::new(),
261 init: Some(Box::new(f)),
262 }
263 }
264 pub fn force(&mut self) -> &T {
266 if self.cell.get().is_none() {
267 if let Some(f) = self.init.take() {
268 let _ = self.cell.set(f());
269 }
270 }
271 self.cell.get().expect("OnceCellThunk: init was None")
272 }
273 pub fn is_forced(&self) -> bool {
275 self.cell.get().is_some()
276 }
277}
278#[allow(dead_code)]
280#[derive(Debug, Clone)]
281pub struct CofreeStream<A> {
282 pub elements: Vec<A>,
283 pub period: usize,
284}
285#[allow(dead_code)]
286impl<A: Clone> CofreeStream<A> {
287 pub fn from_periodic(seed: Vec<A>) -> Self {
288 let len = seed.len().max(1);
289 CofreeStream {
290 elements: seed,
291 period: len,
292 }
293 }
294 pub fn extract(&self) -> &A {
295 &self.elements[0]
296 }
297 pub fn tail(&self) -> Self {
298 if self.elements.len() <= 1 {
299 return self.clone();
300 }
301 let mut new_elems = self.elements[1..].to_vec();
302 new_elems.push(self.elements[0].clone());
303 CofreeStream {
304 elements: new_elems,
305 period: self.period,
306 }
307 }
308 pub fn nth(&self, n: usize) -> &A {
309 &self.elements[n % self.elements.len()]
310 }
311 pub fn map<B, F: Fn(&A) -> B>(&self, f: F) -> CofreeStream<B> {
312 CofreeStream {
313 elements: self.elements.iter().map(f).collect(),
314 period: self.period,
315 }
316 }
317}
318#[allow(dead_code)]
320#[derive(Debug, Clone)]
321pub struct ComputeNode<T: Clone> {
322 pub name: String,
323 pub value: Option<T>,
324 pub deps: Vec<String>,
325 pub is_dirty: bool,
326}
327#[allow(dead_code)]
328impl<T: Clone> ComputeNode<T> {
329 pub fn new(name: &str) -> Self {
330 ComputeNode {
331 name: name.to_string(),
332 value: None,
333 deps: Vec::new(),
334 is_dirty: true,
335 }
336 }
337 pub fn add_dep(&mut self, dep: &str) {
338 self.deps.push(dep.to_string());
339 }
340 pub fn set_value(&mut self, val: T) {
341 self.value = Some(val);
342 self.is_dirty = false;
343 }
344 pub fn invalidate(&mut self) {
345 self.value = None;
346 self.is_dirty = true;
347 }
348 pub fn get(&self) -> Option<&T> {
349 self.value.as_ref()
350 }
351}
352#[allow(dead_code)]
358pub struct GameArena {
359 moves: Vec<(usize, String)>,
361 question_counter: usize,
363}
364#[allow(dead_code)]
365impl GameArena {
366 pub fn new() -> Self {
368 Self {
369 moves: Vec::new(),
370 question_counter: 0,
371 }
372 }
373 pub fn ask(&mut self) -> usize {
375 let q = self.question_counter;
376 self.question_counter += 1;
377 q
378 }
379 pub fn answer(&mut self, q: usize, v: impl Into<String>) {
381 self.moves.push((q, v.into()));
382 }
383 pub fn get_answer(&self, q: usize) -> Option<&str> {
385 self.moves
386 .iter()
387 .find(|(qi, _)| *qi == q)
388 .map(|(_, a)| a.as_str())
389 }
390 pub fn move_count(&self) -> usize {
392 self.moves.len()
393 }
394 pub fn is_complete(&self) -> bool {
396 let answered: std::collections::HashSet<usize> =
397 self.moves.iter().map(|(q, _)| *q).collect();
398 (0..self.question_counter).all(|q| answered.contains(&q))
399 }
400}
401#[derive(Debug, Clone)]
403pub struct Delayed<T> {
404 value: T,
405 delay_steps: usize,
406 elapsed: usize,
407}
408impl<T: Clone> Delayed<T> {
409 pub fn new(value: T, steps: usize) -> Self {
411 Self {
412 value,
413 delay_steps: steps,
414 elapsed: 0,
415 }
416 }
417 pub fn step(&mut self) -> Option<T> {
419 self.elapsed += 1;
420 if self.elapsed >= self.delay_steps {
421 Some(self.value.clone())
422 } else {
423 None
424 }
425 }
426 pub fn is_ready(&self) -> bool {
428 self.elapsed >= self.delay_steps
429 }
430 pub fn remaining(&self) -> usize {
432 self.delay_steps.saturating_sub(self.elapsed)
433 }
434}
435#[allow(dead_code)]
437#[derive(Debug, Clone, PartialEq)]
438pub enum ThunkState<T> {
439 Unevaluated,
440 Evaluating,
441 Evaluated(T),
442 Error(String),
443}
444#[allow(dead_code)]
445impl<T: Clone> ThunkState<T> {
446 pub fn is_value(&self) -> bool {
447 matches!(self, ThunkState::Evaluated(_))
448 }
449 pub fn is_blackhole(&self) -> bool {
450 matches!(self, ThunkState::Evaluating)
451 }
452 pub fn get_value(&self) -> Option<&T> {
453 match self {
454 ThunkState::Evaluated(v) => Some(v),
455 _ => None,
456 }
457 }
458 pub fn enter(&mut self) -> bool {
459 match self {
460 ThunkState::Unevaluated => {
461 *self = ThunkState::Evaluating;
462 true
463 }
464 ThunkState::Evaluating => false,
465 _ => false,
466 }
467 }
468 pub fn fill(&mut self, val: T) {
469 *self = ThunkState::Evaluated(val);
470 }
471 pub fn fail(&mut self, msg: &str) {
472 *self = ThunkState::Error(msg.to_string());
473 }
474}
475#[allow(dead_code)]
479pub struct ThunkKleisli<A, B> {
480 arrow: Box<dyn Fn(A) -> Option<B>>,
481}
482#[allow(dead_code)]
483impl<A: 'static, B: Clone + 'static> ThunkKleisli<A, B> {
484 pub fn new<F: Fn(A) -> Option<B> + 'static>(f: F) -> Self {
486 Self { arrow: Box::new(f) }
487 }
488 pub fn apply(&self, a: A) -> Option<B> {
490 (self.arrow)(a)
491 }
492 pub fn compose<C: Clone + 'static>(self, other: ThunkKleisli<B, C>) -> ThunkKleisli<A, C> {
494 ThunkKleisli::new(move |a| {
495 let b = (self.arrow)(a)?;
496 other.apply(b)
497 })
498 }
499}
500#[allow(dead_code)]
502#[derive(Debug, Clone)]
503pub enum Suspension<A> {
504 Done(A),
505 Suspended(String),
506 Aborted(String),
507}
508#[allow(dead_code)]
509impl<A: Clone> Suspension<A> {
510 pub fn pure(a: A) -> Self {
511 Suspension::Done(a)
512 }
513 pub fn suspend(desc: &str) -> Self {
514 Suspension::Suspended(desc.to_string())
515 }
516 pub fn abort(msg: &str) -> Self {
517 Suspension::Aborted(msg.to_string())
518 }
519 pub fn is_done(&self) -> bool {
520 matches!(self, Suspension::Done(_))
521 }
522 pub fn map<B: Clone, F: Fn(A) -> B>(self, f: F) -> Suspension<B> {
523 match self {
524 Suspension::Done(a) => Suspension::Done(f(a)),
525 Suspension::Suspended(d) => Suspension::Suspended(d),
526 Suspension::Aborted(e) => Suspension::Aborted(e),
527 }
528 }
529 pub fn and_then<B: Clone, F: Fn(A) -> Suspension<B>>(self, f: F) -> Suspension<B> {
530 match self {
531 Suspension::Done(a) => f(a),
532 Suspension::Suspended(d) => Suspension::Suspended(d),
533 Suspension::Aborted(e) => Suspension::Aborted(e),
534 }
535 }
536}
537#[allow(dead_code)]
542pub struct ComonadCtx<E, A> {
543 pub(super) env: E,
544 pub(super) focus: A,
545}
546#[allow(dead_code)]
547impl<E: Clone, A: Clone> ComonadCtx<E, A> {
548 pub fn new(env: E, focus: A) -> Self {
550 Self { env, focus }
551 }
552 pub fn extract(&self) -> A {
554 self.focus.clone()
555 }
556 pub fn duplicate(&self) -> ComonadCtx<E, ComonadCtx<E, A>> {
558 ComonadCtx {
559 env: self.env.clone(),
560 focus: self.clone(),
561 }
562 }
563 pub fn extend<B, F: Fn(&ComonadCtx<E, A>) -> B>(&self, f: F) -> ComonadCtx<E, B> {
565 ComonadCtx {
566 env: self.env.clone(),
567 focus: f(self),
568 }
569 }
570 pub fn map<B, F: FnOnce(A) -> B>(self, f: F) -> ComonadCtx<E, B> {
572 ComonadCtx {
573 env: self.env,
574 focus: f(self.focus),
575 }
576 }
577 pub fn env(&self) -> &E {
579 &self.env
580 }
581}
582#[derive(Default)]
584pub struct DeferredPool<T> {
585 pending: std::collections::HashMap<usize, Box<dyn FnOnce() -> T>>,
586 resolved: std::collections::HashMap<usize, T>,
587 next_id: usize,
588}
589impl<T> DeferredPool<T> {
590 pub fn new() -> Self {
592 Self {
593 pending: std::collections::HashMap::new(),
594 resolved: std::collections::HashMap::new(),
595 next_id: 0,
596 }
597 }
598 pub fn submit<F: FnOnce() -> T + 'static>(&mut self, f: F) -> usize {
600 let id = self.next_id;
601 self.next_id += 1;
602 self.pending.insert(id, Box::new(f));
603 id
604 }
605 pub fn force(&mut self, id: usize) -> Option<&T> {
607 if !self.resolved.contains_key(&id) {
608 if let Some(f) = self.pending.remove(&id) {
609 self.resolved.insert(id, f());
610 }
611 }
612 self.resolved.get(&id)
613 }
614 pub fn force_all(&mut self) {
616 let ids: Vec<usize> = self.pending.keys().copied().collect();
617 for id in ids {
618 self.force(id);
619 }
620 }
621 pub fn pending_count(&self) -> usize {
623 self.pending.len()
624 }
625 pub fn resolved_count(&self) -> usize {
627 self.resolved.len()
628 }
629}
630#[allow(clippy::type_complexity)]
635pub struct FixThunk<T: Clone> {
636 memo: std::collections::HashMap<usize, T>,
637 step: Box<dyn Fn(usize, &dyn Fn(usize) -> T) -> T>,
638}
639impl<T: Clone> FixThunk<T> {
640 pub fn new<F>(f: F) -> Self
645 where
646 F: Fn(usize, &dyn Fn(usize) -> T) -> T + 'static,
647 {
648 Self {
649 memo: std::collections::HashMap::new(),
650 step: Box::new(f),
651 }
652 }
653 pub fn compute(&mut self, n: usize) -> T {
655 if let Some(v) = self.memo.get(&n) {
656 return v.clone();
657 }
658 let memo_ref: *mut std::collections::HashMap<usize, T> = &mut self.memo;
659 let lookup = |k: usize| -> T {
660 unsafe { (*memo_ref).get(&k).cloned() }.expect("missing cached value")
661 };
662 let v = (self.step)(n, &lookup);
663 self.memo.insert(n, v.clone());
664 v
665 }
666}
667#[allow(dead_code)]
669pub struct MemoThunk<T: Clone> {
670 cached: Option<T>,
671}
672#[allow(dead_code)]
673impl<T: Clone> MemoThunk<T> {
674 pub fn new() -> Self {
675 MemoThunk { cached: None }
676 }
677 pub fn force_with<F: FnOnce() -> T>(&mut self, f: F) -> T {
678 if let Some(ref val) = self.cached {
679 val.clone()
680 } else {
681 let val = f();
682 self.cached = Some(val.clone());
683 val
684 }
685 }
686 pub fn is_forced(&self) -> bool {
687 self.cached.is_some()
688 }
689 pub fn reset(&mut self) {
690 self.cached = None;
691 }
692}
693#[allow(dead_code)]
695pub struct LazyLinkedStream<T> {
696 pub head: T,
697 pub tail_fn: Box<dyn Fn() -> Option<Box<LazyLinkedStream<T>>>>,
698}
699#[allow(dead_code)]
700impl<T: Clone + 'static> LazyLinkedStream<T> {
701 pub fn singleton(val: T) -> Self {
702 LazyLinkedStream {
703 head: val,
704 tail_fn: Box::new(|| None),
705 }
706 }
707 pub fn take_n(&self, n: usize) -> Vec<T> {
708 let mut result = vec![self.head.clone()];
709 let mut current = (self.tail_fn)();
710 while result.len() < n {
711 match current {
712 None => break,
713 Some(node) => {
714 result.push(node.head.clone());
715 current = (node.tail_fn)();
716 }
717 }
718 }
719 result
720 }
721}
722#[derive(Debug, Clone)]
724pub enum Deferred<T> {
725 Now(T),
727 Later(usize),
729}
730impl<T: Clone> Deferred<T> {
731 pub fn now(v: T) -> Self {
733 Self::Now(v)
734 }
735 pub fn later(id: usize) -> Self {
737 Self::Later(id)
738 }
739 pub fn is_ready(&self) -> bool {
741 matches!(self, Deferred::Now(_))
742 }
743 pub fn resolve_or<F: FnOnce(usize) -> T>(self, f: F) -> T {
745 match self {
746 Deferred::Now(v) => v,
747 Deferred::Later(id) => f(id),
748 }
749 }
750 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Deferred<U> {
752 match self {
753 Deferred::Now(v) => Deferred::Now(f(v)),
754 Deferred::Later(id) => Deferred::Later(id),
755 }
756 }
757}
758#[allow(dead_code)]
762pub enum ITreeNode<E, R> {
763 Ret(R),
765 Tau(Box<dyn FnOnce() -> ITreeNode<E, R>>),
767 Vis(E, Box<dyn Fn(usize) -> ITreeNode<E, R>>),
769}
770#[allow(dead_code)]
771impl<E: Clone, R: Clone> ITreeNode<E, R> {
772 pub fn ret(r: R) -> Self {
774 ITreeNode::Ret(r)
775 }
776 pub fn tau<F: FnOnce() -> ITreeNode<E, R> + 'static>(f: F) -> Self {
778 ITreeNode::Tau(Box::new(f))
779 }
780 pub fn vis<K: Fn(usize) -> ITreeNode<E, R> + 'static>(e: E, k: K) -> Self {
782 ITreeNode::Vis(e, Box::new(k))
783 }
784 pub fn run(self, fuel: usize) -> Option<R> {
786 let mut current = self;
787 for _ in 0..fuel {
788 match current {
789 ITreeNode::Ret(r) => return Some(r),
790 ITreeNode::Tau(f) => {
791 current = f();
792 }
793 ITreeNode::Vis(_, _) => return None,
794 }
795 }
796 None
797 }
798}