narust_158/language/features/
compound_term.rs

1//! 📄OpenNARS `nars.language.CompoundTerm`
2//! * ⚠️不包含与NAL-6有关的「变量」逻辑
3//!   * 📄`isConstant`、`renameVariables`
4//! * ⚠️不包含与「记忆区」有关的方法
5//!   * 📄`addComponents`、`reduceComponents`
6//! * ✅【2024-06-14 13:41:30】初步完成对其内方法的更新
7//! * ✅【2024-06-14 14:43:30】初步完成单元测试
8//!
9//! # 方法列表
10//! 🕒最后更新:【2024-06-14 10:29:57】
11//!
12//! * `isCommutative`
13//! * `size`
14//! * `componentAt`
15//! * `getComponents`
16//! * `cloneComponents`
17//! * `containComponent`
18//! * `containTerm`
19//! * `containAllComponents`
20//! * `setTermWhenDealingVariables`
21//! * `updateAfterRenameVariables`
22//! * `updateNameAfterRenameVariables`
23//! * `reorderComponents`
24//!
25//! # 📄OpenNARS
26//!
27//! A CompoundTerm is a Term with internal (syntactic) structure
28//!
29//! A CompoundTerm consists of a term operator with one or more component Terms.
30//!
31//! This abstract class contains default methods for all CompoundTerms.
32
33use crate::language::*;
34use crate::symbols::*;
35use nar_dev_utils::matches_or;
36use narsese::api::{GetCapacity, TermCapacity};
37use std::{
38    fmt::{Display, Formatter},
39    ops::{Deref, DerefMut},
40};
41
42/// 对词项数组的外加方法
43/// * 🎯复现OpenNARS中ArrayList的remove, removeAll等方法
44pub(in crate::language) mod vec_utils {
45    use crate::language::Term;
46
47    /// 从[`Vec`]中移除一个词项
48    pub fn remove(vec: &mut Vec<Term>, term: &Term) -> bool {
49        /* 📄Java ArrayList
50        final Object[] es = elementData;
51        final int size = this.size;
52        int i = 0;
53        found: {
54            if (o == null) {
55                for (; i < size; i++)
56                    if (es[i] == null)
57                        break found;
58            } else {
59                for (; i < size; i++)
60                    if (o.equals(es[i]))
61                        break found;
62            }
63            return false;
64        }
65        fastRemove(es, i);
66        return true; */
67        let position = vec.iter().position(|t| t == term);
68        match position {
69            Some(i) => {
70                vec.remove(i);
71                true
72            }
73            None => false,
74        }
75    }
76
77    /// 在[`Vec`]中移除多个词项
78    pub fn remove_all(vec: &mut Vec<Term>, terms: &[Term]) -> bool {
79        // * 🚩暂且直接遍历做删除
80        // vec.retain(|t| !terms.contains(t)); // ! 📌【2024-06-16 11:59:47】不使用:可能对一个term in terms会删掉多个词项
81        let mut removed = false;
82        for term in terms {
83            // * 🚩始终运行,不使用惰性的any
84            if remove(vec, term) {
85                removed = true;
86            }
87        }
88        removed
89    }
90
91    /// 词项数组取交集
92    /// * 📌根据[`==`](Eq::eq)
93    pub fn retain_all(vec: &mut Vec<Term>, terms: &[Term]) {
94        vec.retain(|t| terms.contains(t));
95    }
96}
97
98// 词项与「复合词项」(内部元素)无关的特性
99impl Term {
100    /// 🆕用于判断是否为「纯复合词项」
101    /// * ⚠️**不**包括陈述
102    pub fn instanceof_compound_pure(&self) -> bool {
103        matches!(
104            self.identifier(),
105            SET_EXT_OPERATOR
106                | SET_INT_OPERATOR
107                | INTERSECTION_EXT_OPERATOR
108                | INTERSECTION_INT_OPERATOR
109                | DIFFERENCE_EXT_OPERATOR
110                | DIFFERENCE_INT_OPERATOR
111                | PRODUCT_OPERATOR
112                | IMAGE_EXT_OPERATOR
113                | IMAGE_INT_OPERATOR
114                | CONJUNCTION_OPERATOR
115                | DISJUNCTION_OPERATOR
116                | NEGATION_OPERATOR
117        )
118    }
119
120    /// 🆕用于判断词项是否为「指定类型的复合词项」,并尝试返回「复合词项」的引用信息
121    /// * 📌包括陈述
122    /// * 🚩模式匹配后返回一个[`Option`],只在其为「符合指定类型的词项」时为[`Some`]
123    /// * 🚩返回不可变引用
124    #[must_use]
125    pub fn as_compound_type(&self, compound_class: impl AsRef<str>) -> Option<CompoundTermRef> {
126        matches_or! {
127            ?self.as_compound(),
128            Some(compound)
129                // * 🚩标识符相等
130                if compound_class.as_ref() == self.identifier()
131                // * 🚩内部(类型相等)的复合词项
132                => compound
133        }
134    }
135
136    /// 🆕用于判断词项是否为复合词项
137    /// * 📌包括陈述
138    /// * 🚩模式匹配后返回一个[`Option`],只在其为「符合指定类型的词项」时为[`Some`]
139    /// * 🚩返回标识符与内部所有元素的所有权
140    #[must_use]
141    pub fn unwrap_compound_id_components(self) -> Option<(String, Box<[Term]>)> {
142        matches_or! {
143            ?self.unwrap_id_comp(),
144            // * 🚩匹配到如下结构⇒返回Some,否则返回None
145            (
146                // * 🚩标识符
147                identifier,
148                // * 🚩内容为「复合词项」
149                TermComponents::Compound(terms)
150            )
151            // * 🚩返回内容
152            => (identifier, terms)
153        }
154    }
155
156    /// 🆕用于判断词项是否为复合词项
157    /// * 📌包括陈述
158    /// * 🚩模式匹配后返回一个[`Option`],只在其为「符合指定类型的词项」时为[`Some`]
159    /// * 🚩返回内部所有元素的所有权
160    #[must_use]
161    pub fn unwrap_compound_components(self) -> Option<Box<[Term]>> {
162        matches_or! {
163            ?self.unwrap_id_comp(),
164            // * 🚩匹配到如下结构⇒返回Some,否则返回None
165            (
166                _,
167                // * 🚩内容为「复合词项」
168                TermComponents::Compound(terms)
169            )
170            // * 🚩返回内容
171            => terms
172        }
173    }
174
175    /// 🆕用于判断词项是否为「指定类型的复合词项」
176    /// * 📌包括陈述
177    /// * 🚩模式匹配后返回一个[`Option`],只在其为「符合指定类型的词项」时为[`Some`]
178    /// * 🚩返回内部所有元素的所有权
179    #[must_use]
180    pub fn unwrap_compound_type_components(
181        self,
182        compound_class: impl AsRef<str>,
183    ) -> Option<Box<[Term]>> {
184        matches_or! {
185            ?self.unwrap_id_comp(),
186            // * 🚩匹配到如下结构⇒返回Some,否则返回None
187            (
188                identifier,
189                // * 🚩内容为「复合词项」
190                TermComponents::Compound(terms)
191            )
192            // * 🚩标识符相等
193            if identifier.as_str() == compound_class.as_ref()
194            // * 🚩返回内容
195            => terms
196        }
197    }
198
199    /// 🆕用于判断是否为「复合词项」
200    /// * ⚠️包括陈述
201    /// * 📄OpenNARS `instanceof CompoundTerm` 逻辑
202    #[inline(always)]
203    pub fn instanceof_compound(&self) -> bool {
204        self.instanceof_compound_pure() || self.instanceof_statement()
205    }
206
207    /// 🆕用于判断是否为「外延集」
208    /// * 📄OpenNARS`instanceof SetExt`逻辑
209    /// * 🎯[`crate::inference`]推理规则分派
210    #[inline(always)]
211    pub fn instanceof_set_ext(&self) -> bool {
212        self.identifier() == SET_EXT_OPERATOR
213    }
214
215    /// 🆕用于判断是否为「内涵集」
216    /// * 📄OpenNARS`instanceof SetInt`逻辑
217    /// * 🎯[`crate::inference`]推理规则分派
218    #[inline(always)]
219    pub fn instanceof_set_int(&self) -> bool {
220        self.identifier() == SET_INT_OPERATOR
221    }
222
223    /// 🆕用于判断是否为「词项集」
224    /// * 📄OpenNARS`instanceof SetExt || instanceof SetInt`逻辑
225    #[inline(always)]
226    pub fn instanceof_set(&self) -> bool {
227        self.instanceof_set_ext() || self.instanceof_set_int()
228    }
229
230    /// 🆕用于判断是否为「外延交」
231    /// * 📄OpenNARS`instanceof IntersectionExt`逻辑
232    /// * 🎯[`crate::inference`]推理规则分派
233    #[inline(always)]
234    pub fn instanceof_intersection_ext(&self) -> bool {
235        self.identifier() == INTERSECTION_EXT_OPERATOR
236    }
237
238    /// 🆕用于判断是否为「内涵交」
239    /// * 📄OpenNARS`instanceof IntersectionInt`逻辑
240    /// * 🎯[`crate::inference`]推理规则分派
241    #[inline(always)]
242    pub fn instanceof_intersection_int(&self) -> bool {
243        self.identifier() == INTERSECTION_INT_OPERATOR
244    }
245
246    /// 🆕用于判断是否为「词项交集」
247    /// * 📄OpenNARS`instanceof IntersectionExt || instanceof IntersectionInt`逻辑
248    /// * 🎯首次用于[`crate::inference::StructuralRules::__switch_order`]
249    #[inline(always)]
250    pub fn instanceof_intersection(&self) -> bool {
251        self.instanceof_intersection_ext() || self.instanceof_intersection_int()
252    }
253
254    /// 🆕用于判断是否为「外延差」
255    /// * 📄OpenNARS`instanceof DifferenceExt`逻辑
256    /// * 🎯[`crate::inference`]推理规则分派
257    #[inline(always)]
258    pub fn instanceof_difference_ext(&self) -> bool {
259        self.identifier() == DIFFERENCE_EXT_OPERATOR
260    }
261
262    /// 🆕用于判断是否为「内涵差」
263    /// * 📄OpenNARS`instanceof DifferenceInt`逻辑
264    /// * 🎯[`crate::inference`]推理规则分派
265    #[inline(always)]
266    pub fn instanceof_difference_int(&self) -> bool {
267        self.identifier() == DIFFERENCE_INT_OPERATOR
268    }
269
270    /// 🆕用于判断是否为「词项差集」
271    /// * 📄OpenNARS`instanceof DifferenceExt || instanceof DifferenceInt`逻辑
272    #[inline(always)]
273    pub fn instanceof_difference(&self) -> bool {
274        self.instanceof_difference_ext() || self.instanceof_difference_int()
275    }
276
277    /// 🆕用于判断是否为「乘积」
278    /// * 📄OpenNARS`instanceof Product`逻辑
279    /// * 🎯[`crate::inference`]推理规则分派
280    #[inline(always)]
281    pub fn instanceof_product(&self) -> bool {
282        self.identifier() == PRODUCT_OPERATOR
283    }
284
285    /// 🆕用于判断是否为「外延像」
286    /// * 📄OpenNARS`instanceof ImageExt`逻辑
287    /// * 🎯[`crate::inference`]推理规则分派
288    #[inline(always)]
289    pub fn instanceof_image_ext(&self) -> bool {
290        self.identifier() == IMAGE_EXT_OPERATOR
291    }
292
293    /// 🆕用于判断是否为「内涵像」
294    /// * 📄OpenNARS`instanceof ImageInt`逻辑
295    /// * 🎯[`crate::inference`]推理规则分派
296    #[inline(always)]
297    pub fn instanceof_image_int(&self) -> bool {
298        self.identifier() == IMAGE_INT_OPERATOR
299    }
300
301    /// 🆕用于判断是否为「像」
302    /// * 📄OpenNARS`instanceof ImageExt || instanceof ImageInt`逻辑
303    #[inline(always)]
304    pub fn instanceof_image(&self) -> bool {
305        self.instanceof_image_ext() || self.instanceof_image_int()
306    }
307
308    /// 🆕用于判断是否为「合取」
309    /// * 📄OpenNARS`instanceof Conjunction`逻辑
310    /// * 🎯[`crate::inference`]推理规则分派
311    #[inline(always)]
312    pub fn instanceof_conjunction(&self) -> bool {
313        self.identifier() == CONJUNCTION_OPERATOR
314    }
315
316    /// 🆕用于判断是否为「析取」
317    /// * 📄OpenNARS`instanceof Disjunction`逻辑
318    /// * 🎯[`crate::inference`]推理规则分派
319    #[inline(always)]
320    pub fn instanceof_disjunction(&self) -> bool {
321        self.identifier() == DISJUNCTION_OPERATOR
322    }
323    /// 🆕用于判断是否为「词项差集」
324    /// * 📄OpenNARS`instanceof Conjunction || instanceof Disjunction`逻辑
325    #[inline(always)]
326    pub fn instanceof_junction(&self) -> bool {
327        self.instanceof_conjunction() || self.instanceof_disjunction()
328    }
329
330    /// 🆕用于判断是否为「否定」
331    /// * 📄OpenNARS`instanceof Negation`逻辑
332    /// * 🎯[`crate::inference`]推理规则分派
333    #[inline(always)]
334    pub fn instanceof_negation(&self) -> bool {
335        self.identifier() == NEGATION_OPERATOR
336    }
337
338    /// 📄OpenNARS `CompoundTerm.isCommutative`
339    /// * 📌对「零元/一元 词项」默认为「不可交换」
340    ///   * 📜返回`false`
341    ///   * 📄OpenNARS中`Negation`的定义(即默认「不可交换」)
342    ///
343    /// # 📄OpenNARS
344    ///
345    /// Check if the order of the components matters
346    ///
347    /// Commutative CompoundTerms: Sets, Intersections
348    /// Commutative Statements: Similarity, Equivalence (except the one with a temporal order)
349    /// Commutative CompoundStatements: Disjunction, Conjunction (except the one with a temporal order)
350    #[doc(alias = "is_symmetric")]
351    pub fn is_commutative(&self) -> bool {
352        matches!(
353            self.identifier(),
354            // Commutative CompoundTerms
355            SET_EXT_OPERATOR
356                | SET_INT_OPERATOR
357                | INTERSECTION_EXT_OPERATOR
358                | INTERSECTION_INT_OPERATOR
359                // Commutative Statements
360                | SIMILARITY_RELATION
361                | EQUIVALENCE_RELATION
362                // Commutative CompoundStatements
363                | DISJUNCTION_OPERATOR
364                | CONJUNCTION_OPERATOR
365        )
366    }
367
368    /// 判断和另一词项是否「结构匹配」
369    /// * 🎯变量替换中的模式匹配
370    /// * 🚩类型匹配 & 组分匹配
371    /// * ⚠️非递归:不会递归比较「组分是否对应匹配」
372    #[inline(always)]
373    pub fn structural_match(&self, other: &Self) -> bool {
374        self.is_same_type(other)
375        // * 🚩内部组分的「结构匹配」而非自身匹配
376            && self
377                .components()
378                .structural_match(other.components())
379    }
380
381    /// 🆕判断是否真的是「复合词项」
382    /// * 🚩通过判断「内部元素枚举」的类型实现
383    /// * 🎯用于后续「作为复合词项」使用
384    ///   * ✨以此在程序层面表示「复合词项」类型
385    pub fn is_compound(&self) -> bool {
386        matches!(self.components(), TermComponents::Compound(..))
387    }
388
389    /// 🆕尝试将词项作为「复合词项」
390    /// * 📌通过判断「内部元素枚举」的类型实现
391    /// * 🚩在其内部元素不是「复合词项」时,会返回`None`
392    #[must_use]
393    pub fn as_compound(&self) -> Option<CompoundTermRef> {
394        matches_or!(
395            ?self.components(),
396            TermComponents::Compound(ref c) => CompoundTermRef {
397                inner: self,
398                components: c
399            }
400        )
401    }
402
403    /// 🆕尝试将词项作为「复合词项」
404    /// * 📌通过判断「内部元素枚举」的类型实现
405    /// * 🚩在其内部元素不是「复合词项」时,会返回`None`
406    #[must_use]
407    pub fn as_compound_and(
408        &self,
409        predicate: impl FnOnce(&CompoundTermRef) -> bool,
410    ) -> Option<CompoundTermRef> {
411        match self.as_compound() {
412            Some(compound) if predicate(&compound) => Some(compound),
413            _ => None,
414        }
415    }
416
417    /// 🆕尝试将词项作为「复合词项」(未检查)
418    /// * 🚩通过判断「内部元素枚举」的类型实现
419    ///
420    /// # Safety
421    ///
422    /// * ⚠️代码是不安全的:必须在解包前已经假定是「复合词项」
423    /// * 📄逻辑参考自[`Option::unwrap_unchecked`]
424    #[must_use]
425    pub unsafe fn as_compound_unchecked(&self) -> CompoundTermRef {
426        // * 🚩在debug模式下检查
427        debug_assert!(self.is_compound(), "转换前必须假定其为复合词项");
428        // * 🚩正式开始解引用
429        match self.components() {
430            TermComponents::Compound(ref c) => CompoundTermRef {
431                inner: self,
432                components: c,
433            },
434            // SAFETY: the safety contract must be upheld by the caller.
435            _ => unsafe { core::hint::unreachable_unchecked() },
436        }
437    }
438
439    /// 🆕尝试将词项作为「复合词项」
440    /// * ℹ️[`Self::as_compound`]的可变版本
441    #[must_use]
442    pub fn as_compound_mut(&mut self) -> Option<CompoundTermRefMut> {
443        matches_or! {
444            // * 📌此处需要可变借用,才能在下头正常把Box变成可变引用(而无需Deref)
445            // * ❌使用`ref mut`不能达到目的:解引用后还是Box
446            ?self.components_mut(),
447            TermComponents::Compound(components) => CompoundTermRefMut {
448                // * 🚩【2024-06-15 14:00:09】此处创建裸指针,是安全行为(解引用才是不安全行为)
449                // * 📄具体使用参见[`CompoundTermRefMut::components`]
450                components: &mut **components as *mut [Term],
451                inner   :self,
452            }
453        }
454    }
455
456    /// 🆕尝试将词项作为「可变复合词项」(未检查)
457    /// * 🚩通过判断「内部元素枚举」的类型实现
458    ///
459    /// # Safety
460    ///
461    /// * ⚠️代码是不安全的:必须在解包前已经假定是「复合词项」
462    /// * 📄逻辑参考自[`Option::unwrap_unchecked`]
463    #[must_use]
464    pub unsafe fn as_compound_mut_unchecked(&mut self) -> CompoundTermRefMut {
465        // * 🚩在debug模式下检查
466        debug_assert!(self.is_compound(), "转换前必须假定其为复合词项");
467        // * 🚩正式开始解引用
468        match self.components_mut() {
469            TermComponents::Compound(components) => CompoundTermRefMut {
470                // * 🚩【2024-06-15 14:00:09】此处创建裸指针,是安全行为(解引用才是不安全行为)
471                // * 📄具体使用参见[`CompoundTermRefMut::components`]
472                components: &mut **components as *mut [Term],
473                inner: self,
474            },
475            // SAFETY: the safety contract must be upheld by the caller.
476            _ => unsafe { core::hint::unreachable_unchecked() },
477        }
478    }
479}
480
481/// 从NAL语义上判断词项的「容量」
482impl GetCapacity for Term {
483    fn get_capacity(&self) -> TermCapacity {
484        use TermCapacity::*;
485        match self.identifier() {
486            // * 🚩原子:词语、占位符、变量
487            WORD | PLACEHOLDER | VAR_INDEPENDENT | VAR_DEPENDENT | VAR_QUERY => Atom,
488            // * 🚩一元:否定
489            NEGATION_OPERATOR => Unary,
490            // * 🚩二元序列:差集、继承、蕴含 | ❌不包括「实例」「属性」「实例属性」
491            DIFFERENCE_EXT_OPERATOR
492            | DIFFERENCE_INT_OPERATOR
493            | INHERITANCE_RELATION
494            | IMPLICATION_RELATION => BinaryVec,
495            // * 🚩二元集合:相似、等价
496            SIMILARITY_RELATION | EQUIVALENCE_RELATION => BinarySet,
497            // * 🚩多元序列:乘积、像
498            PRODUCT_OPERATOR | IMAGE_EXT_OPERATOR | IMAGE_INT_OPERATOR => Vec,
499            // * 🚩多元集合:词项集、交集、合取、析取
500            SET_EXT_OPERATOR
501            | SET_INT_OPERATOR
502            | INTERSECTION_EXT_OPERATOR
503            | INTERSECTION_INT_OPERATOR
504            | CONJUNCTION_OPERATOR
505            | DISJUNCTION_OPERATOR => Set,
506            // * 🚩其它⇒panic(不应出现)
507            id => panic!("Unexpected compound term identifier: {id}"),
508        }
509    }
510}
511
512/// 🆕作为「复合词项引用」的词项类型
513/// * 🎯在程序类型层面表示一个「复合词项」(不可变引用)
514#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
515pub struct CompoundTermRef<'a> {
516    /// 复合词项整体
517    pub inner: &'a Term,
518    /// 复合词项的元素列表
519    pub components: &'a [Term],
520}
521
522impl<'s> CompoundTermRef<'s> {
523    /// 📄OpenNARS `CompoundTerm.size`
524    /// * 🚩直接链接到[`TermComponents`]的属性
525    /// * ⚠️对「像」不包括「像占位符」
526    ///   * 📄`(/, A, _, B)`的`size`为`2`而非`3`
527    ///
528    /// # 📄OpenNARS
529    ///
530    /// get the number of components
531    #[inline]
532    pub fn size(&self) -> usize {
533        self.components.len()
534    }
535
536    /// 📄OpenNARS `CompoundTerm.componentAt`
537    /// * 🚩直接连接到[`TermComponents`]的方法
538    /// * ⚠️对「像」不受「像占位符」位置影响
539    ///
540    /// # 📄OpenNARS
541    ///
542    /// get a component by index
543    #[inline]
544    pub fn component_at(self, index: usize) -> Option<&'s Term> {
545        self.components.get(index)
546    }
547
548    /// 📄OpenNARS `CompoundTerm.componentAt`
549    /// * 🆕unsafe版本:若已知词项的组分数,则可经此对症下药
550    /// * 🚩直接连接到[`TermComponents`]的方法
551    /// * ⚠️对「像」不受「像占位符」位置影响
552    ///
553    /// # Safety
554    ///
555    /// ⚠️只有在「确保索引不会越界」才不会引发panic
556    ///
557    /// # 📄OpenNARS
558    ///
559    /// get a component by index
560    #[inline]
561    pub unsafe fn component_at_unchecked(&self, index: usize) -> &Term {
562        self.components.get_unchecked(index)
563    }
564
565    /// 📄OpenNARS `CompoundTerm.getComponents`
566    /// * 🚩直接连接到[`TermComponents`]的方法
567    /// * 🚩【2024-04-21 16:11:59】目前只需不可变引用
568    ///   * 🔎OpenNARS中大部分用法是「只读」情形
569    /// * 🚩自改版:仅在复合词项「移除元素」时使用
570    ///
571    /// # 📄OpenNARS
572    ///
573    /// Get the component list
574    #[inline]
575    pub(super) fn get_components(&self) -> impl Iterator<Item = &Term> {
576        self.components.iter()
577    }
578
579    /// 🆕改版 `CompoundTerm.indexOfComponent`
580    ///
581    /// @param t [&]
582    /// @return [] index or -1
583    ///
584    pub fn index_of_component(&self, t: &Term) -> Option<usize> {
585        self.components.iter().position(|term| term == t)
586    }
587
588    /// 📄OpenNARS `CompoundTerm.cloneComponents`
589    /// * 🚩【2024-06-14 10:43:03】遵照改版原意,使用变长数组
590    ///   * ℹ️后续需要增删操作
591    ///   * 📝无论如何也绕不开[`Vec`]
592    ///
593    /// # 📄OpenNARS
594    ///
595    /// Clone the component list
596    pub fn clone_components(&self) -> Vec<Term> {
597        self.components.to_vec()
598    }
599
600    /// 📄OpenNARS `CompoundTerm.cloneComponents`
601    /// * 🚩只拷贝所有元素的引用,无需拷贝其中的值
602    pub fn clone_component_refs(&self) -> Vec<&Term> {
603        self.components.iter().collect()
604    }
605
606    /// 📄OpenNARS `CompoundTerm.containComponent`
607    /// * 🎯检查其是否包含**直接**组分
608    /// * 🚩直接基于已有迭代器方法
609    ///
610    /// # 📄OpenNARS
611    ///
612    /// Check whether the compound contains a certain component
613    pub fn contain_component(&self, component: &Term) -> bool {
614        self.get_components().any(|term| term == component)
615    }
616
617    /// 📄OpenNARS `CompoundTerm.containTerm`
618    /// * 🎯检查其是否**递归**包含组分
619    /// * 🚩直接基于已有迭代器方法:词项 == 组分 || 词项 in 组分
620    ///
621    /// # 📄OpenNARS
622    ///
623    /// Recursively check if a compound contains a term
624    pub fn contain_term(&self, term: &Term) -> bool {
625        self.get_components()
626            .any(|sub_term| match sub_term.as_compound() {
627                // * 🚩非复合⇒判等
628                None => term == sub_term,
629                // * 🚩复合⇒递归
630                Some(sub_compound) => sub_compound.contain_term(term),
631            })
632    }
633
634    /// 📄OpenNARS `CompoundTerm.containAllComponents`
635    /// * 🎯分情况检查「是否包含所有组分」
636    ///   * 📌同类⇒检查其是否包含`other`的所有组分
637    ///   * 📌异类⇒检查其是否包含`other`作为整体
638    /// * 🚩直接基于已有迭代器方法
639    ///
640    /// # 📄OpenNARS
641    ///
642    /// Check whether the compound contains all components of another term, or that term as a whole
643    pub fn contain_all_components(&self, other: &Term) -> bool {
644        match self.inner.is_same_type(other) {
645            // * 🚩再判断内层是否为复合词项
646            true => match other.as_compound() {
647                // * 🚩复合词项⇒深入一层
648                Some(other) => other
649                    .get_components()
650                    .all(|should_in| self.contain_component(should_in)),
651                _ => false,
652            },
653            false => self.contain_component(other),
654        }
655    }
656
657    /// 🆕作为「条件句」使用
658    /// * 🚩转发到[「陈述」](StatementRef::as_conditional)中
659    ///
660    /// ! ❌【2024-07-05 17:04:02】不再考虑支持「等价」陈述的词项链转换,同时也不再将「等价陈述」视作「条件句」
661    pub fn as_conditional(self) -> Option<(StatementRef<'s>, CompoundTermRef<'s>)> {
662        self.as_statement()?.as_conditional()
663    }
664}
665
666/// 转发「呈现」方法到「内部词项」
667impl Display for CompoundTermRef<'_> {
668    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
669        self.inner.fmt(f)
670    }
671}
672
673/// 向词项本身的自动解引用
674/// * 🎯让「复合词项引用」可以被看作是一个普通的词项
675impl Deref for CompoundTermRef<'_> {
676    type Target = Term;
677
678    fn deref(&self) -> &Self::Target {
679        self.inner
680    }
681}
682
683/// 🆕作为「复合词项引用」的词项类型
684/// * 🎯在程序类型层面表示一个「复合词项」(可变引用)
685/// * ⚠️取舍:因可变引用无法共享,此时需要在构造层面限制
686///   * 📌构造时保证「内部组分」为「复合词项」变种
687#[derive(Debug, PartialEq, Eq, Hash)]
688pub struct CompoundTermRefMut<'a> {
689    /// 复合词项内部的词项整体(自身)
690    pub(super) inner: &'a mut Term,
691    /// 复合词项内部的元素列表
692    /// * ⚠️【2024-06-15 13:45:47】尝试使用裸指针,不安全代码封装安全接口
693    pub(super) components: *mut [Term],
694}
695
696impl CompoundTermRefMut<'_> {
697    /// 获取词项整体
698    pub fn inner(&mut self) -> &mut Term {
699        self.inner
700    }
701
702    /// 获取内部组分
703    /// * 📌【2024-06-15 14:56:33】需要用可变引用`&mut self`保证「独占性」
704    ///
705    /// # Panics
706    ///
707    /// ! ⚠️若使用了非法的构造方式将「非复合词项」构造入此,则将抛出panic
708    pub fn components(&mut self) -> &mut [Term] {
709        // matches_or!(
710        //     self.inner.components,
711        //     TermComponents::Compound(ref mut components) => components,
712        //     unreachable!("CompoundTermRefMut::components 断言失败:不是复合词项: {}", self.inner)
713        // )
714        // * ✅即:不可能在「调用components」与「使用components」之间插入「inner」
715        // * 🚩解引用前(在debug模式下)检查
716        debug_assert!(self.inner.is_compound());
717        // * 🚩解引用
718        // ! SAFETY: 此处保证对整体(整个复合词项)拥有引用
719        unsafe { &mut *self.components }
720    }
721
722    /// 生成一个不可变引用
723    /// * 🚩将自身的所有字段转换为不可变引用,然后构造一个「不可变引用」结构
724    /// * 📌可变引用一定能转换成不可变引用
725    /// * ⚠️与[`AsRef`]与[`Deref`]不同:此处需要返回所有权,而非对目标类型([`Term`])的引用
726    ///   * ❌返回`&CompoundTermRef`会导致「返回临时变量引用」故无法使用
727    /// * ❌【2024-06-15 16:37:07】危险:不能在此【只传引用】,否则将能在「拿出引用」的同时「使用自身」
728    pub fn into_ref<'s>(self) -> CompoundTermRef<'s>
729    where
730        Self: 's,
731    {
732        // * 🚩解引用前(在debug模式下)检查
733        debug_assert!(self.inner.is_compound());
734        // * 🚩传递引用 & 裸指针解引用
735        CompoundTermRef {
736            inner: self.inner,
737            // SAFETY: 自身相当于对词项的可变引用,同时两个字段均保证有效——那就一定能同时转换
738            components: unsafe { &*self.components },
739        }
740    }
741
742    /* ----- variable-related utilities ----- */
743
744    // ! 📌`set_term_when_dealing_variables`现在不再使用:直接在「变量处理」中设置指针所指向的值
745
746    /// 🆕对于「可交换词项」重排其中的元素
747    /// * 🚩【2024-06-13 18:05:40】只在「应用替换」时用到
748    /// * 🚩【2024-06-14 13:37:46】使用「内存交换」魔法代码
749    /// * 🚩包含「排序」「去重」两个作用
750    pub fn reorder_components(&mut self) {
751        // * 🚩构造一个「占位符」并将其与已有组分互换
752        let mut placeholder = TermComponents::Empty;
753        std::mem::swap(&mut placeholder, self.inner.components_mut());
754        // * 🚩将替换后名为「占位符」的实际组分进行「重排去重」得到「新组分」
755        let new_components = placeholder.sort_dedup();
756        // * 🚩将「新组分」赋值回原先的组分,原先位置上的「占位符」被覆盖
757        *self.inner.components_mut() = new_components;
758    }
759}
760
761/// 转发「呈现」方法到「内部词项」
762impl Display for CompoundTermRefMut<'_> {
763    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
764        self.inner.fmt(f)
765    }
766}
767
768/// 向词项本身的自动解引用
769/// * 🎯让「复合词项可变引用」可以被看作是一个普通的词项
770/// * 📌【2024-06-15 15:08:55】安全性保证:在该引用结构使用「元素列表」时,独占引用不允许其再度解引用
771/// * ❌【2024-06-15 15:38:58】不能实现「自动解引用到不可变引用」
772impl Deref for CompoundTermRefMut<'_> {
773    type Target = Term;
774
775    fn deref(&self) -> &Self::Target {
776        self.inner
777    }
778}
779
780/// 向词项本身的自动解引用
781/// * 🎯让「复合词项可变引用」可以被看作是一个普通的词项(可变引用)
782/// * 📌【2024-06-15 15:08:55】安全性保证:在该引用结构使用「元素列表」时,独占引用不允许其再度解引用
783impl DerefMut for CompoundTermRefMut<'_> {
784    fn deref_mut(&mut self) -> &mut Self::Target {
785        self.inner
786    }
787}
788
789/// 可变引用 ⇒ 不可变引用
790impl<'s> From<CompoundTermRefMut<'s>> for CompoundTermRef<'s> {
791    fn from(r: CompoundTermRefMut<'s>) -> Self {
792        r.into_ref()
793    }
794}
795
796/// 具备所有权的复合词项
797/// * 🎯初步决定用于「推理规则」向下分派
798#[derive(Debug, Clone, PartialEq, Eq, Hash)]
799pub struct CompoundTerm {
800    /// 内部词项
801    term: Term,
802}
803
804impl CompoundTerm {
805    /// 获取不可变引用
806    pub fn get_ref(&self) -> CompoundTermRef {
807        // SAFETY: 在构造时,已经检查了是否为复合词项,因此此处无需检查
808        unsafe { self.term.as_compound_unchecked() }
809    }
810
811    /// 获取可变引用
812    pub fn mut_ref(&mut self) -> CompoundTermRefMut {
813        // SAFETY: 在构造时,已经检查了是否为复合词项,因此此处无需检查
814        unsafe { self.term.as_compound_mut_unchecked() }
815    }
816
817    /// 解包为内部成分(主项、系词、谓项)
818    /// * 🎯用于「推理规则」中的新词项生成
819    pub fn unwrap(self) -> (String, Box<[Term]>) {
820        self.term.unwrap_compound_id_components().unwrap()
821    }
822}
823
824/// 仅有的一处入口:从[词项](Term)构造
825impl TryFrom<Term> for CompoundTerm {
826    /// 转换失败时,返回原始词项
827    type Error = Term;
828
829    fn try_from(term: Term) -> Result<Self, Self::Error> {
830        // * 🚩仅在是复合词项时转换成功
831        match term.is_compound() {
832            true => Ok(Self { term }),
833            false => Err(term),
834        }
835    }
836}
837
838/// 出口(转换成词项)
839impl From<CompoundTerm> for Term {
840    fn from(value: CompoundTerm) -> Self {
841        value.term
842    }
843}
844
845/// 方便直接作为词项使用
846/// * ❓是否要滥用此种「类似继承的模式」
847impl Deref for CompoundTerm {
848    type Target = Term;
849
850    fn deref(&self) -> &Self::Target {
851        &self.term
852    }
853}
854
855/// 方便直接作为词项使用(可变)
856impl DerefMut for CompoundTerm {
857    fn deref_mut(&mut self) -> &mut Self::Target {
858        &mut self.term
859    }
860}
861
862/// 内联「显示呈现」
863impl Display for CompoundTerm {
864    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
865        self.term.fmt(f)
866    }
867}
868
869impl CompoundTermRef<'_> {
870    /// 删去元素
871    /// * 🚩从复合词项中删去一个元素,或从同类复合词项中删除所有其内元素,然后尝试约简
872    /// * ⚠️结果可空
873    #[must_use]
874    pub fn reduce_components(
875        // to_be_reduce
876        self,
877        component_to_reduce: &Term,
878    ) -> Option<Term> {
879        let mut components = self.clone_components();
880        // * 🚩试着作为复合词项
881        let success = match (
882            self.is_same_type(component_to_reduce),
883            component_to_reduce.as_compound(),
884        ) {
885            // * 🚩同类⇒移除所有
886            (
887                true,
888                Some(CompoundTermRef {
889                    components: other_components,
890                    ..
891                }),
892            ) => vec_utils::remove_all(&mut components, other_components),
893            // * 🚩异类⇒作为元素移除
894            _ => vec_utils::remove(&mut components, component_to_reduce),
895        };
896        if !success {
897            return None;
898        }
899        // * 🚩尝试约简,或拒绝无效词项
900        match components.len() {
901            // * 🚩元素数量>1⇒以toBeReduce为模板构造新词项
902            // * ✅此处的`self`是共享引用,实现了`Copy`特征
903            2.. => Term::make_compound_term(self, components),
904            // * 🚩元素数量=1⇒尝试「集合约简」
905            1 => match Self::can_extract_to_inner(&self) {
906                true => components.pop(),
907                // ? 为何对「不可约简」的其它复合词项无效,如 (*, A) 就会返回null
908                false => None,
909            },
910            // * 🚩空集⇒始终失败
911            0 => None,
912        }
913    }
914
915    /// 判断「只有一个元素的复合词项」是否与「内部元素」同义
916    /// * 📌即判断该类复合词项是否能做「集合约简」
917    /// * 🎯用于 `(&&, A) => A`、`(||, A) => A`等词项的简化
918    ///   * ⚠️这个「词项」是在「约简之后」考虑的,
919    ///   * 所以可能存在 `(-, A)` 等「整体不合法」的情况
920    /// * 📄
921    #[inline]
922    fn can_extract_to_inner(&self) -> bool {
923        matches!(
924            self.identifier(),
925            CONJUNCTION_OPERATOR
926                | DISJUNCTION_OPERATOR
927                | INTERSECTION_EXT_OPERATOR
928                | INTERSECTION_INT_OPERATOR
929                | DIFFERENCE_EXT_OPERATOR
930                | DIFFERENCE_INT_OPERATOR
931        )
932    }
933
934    /// 替换词项
935    /// * 🚩替换指定索引处的词项,始终返回替换后的新词项
936    /// * 🚩若要替换上的词项为空(⚠️t可空),则与「删除元素」等同
937    /// * ⚠️结果可空
938    #[must_use]
939    pub fn set_component(self, index: usize, term: Option<Term>) -> Option<Term> {
940        let mut list = self.clone_components();
941        list.remove(index);
942        if let Some(term) = term {
943            match (self.is_same_type(&term), term.as_compound()) {
944                // * 🚩同类⇒所有元素并入 | (*, 1, a)[1] = (*, 2, 3) => (*, 1, 2, 3)
945                (
946                    true,
947                    Some(CompoundTermRef {
948                        components: list2, ..
949                    }),
950                ) => {
951                    // * 🚩【2024-06-16 12:20:14】此处选用惰性复制方法:先遍历再复制
952                    for (i, term) in list2.iter().enumerate() {
953                        list.insert(index + i, term.clone());
954                    }
955                }
956                // * 🚩非同类⇒直接插入 | (&&, a, b)[1] = (||, b, c) => (&&, a, (||, b, c))
957                _ => list.insert(index, term),
958            }
959        }
960        // * 🚩以当前词项为模板构造新词项
961        Term::make_compound_term(self, list)
962    }
963}
964
965/// 单元测试
966#[cfg(test)]
967pub(crate) mod tests {
968    use super::*;
969    use crate::{language::test_term::*, ok, option_term, test_term as term, util::AResult};
970    use nar_dev_utils::{asserts, macro_once, unwrap_or_return};
971
972    /// 构建测试用复合词项
973    #[macro_export]
974    macro_rules! test_compound {
975        // 具所有权
976        (box $($t:tt)*) => {
977            CompoundTerm::try_from(term!($($t)*)).unwrap()
978        };
979        // 可变
980        (mut $($t:tt)*) => {
981            term!($($t)*).as_compound_mut().unwrap()
982        };
983        // 不可变
984        ($($t:tt)*) => {
985            term!($($t)*).as_compound().unwrap()
986        };
987    }
988
989    /// 转发,用于模块内部
990    /// * ❌【2024-06-16 13:44:19】无法在内部use
991    macro_rules! compound {
992        ($($t:tt)*) => {
993            test_compound!($($t)*)
994        };
995    }
996
997    /// 「词项」与「复合词项」相关的代码
998    mod term {
999        use super::*;
1000
1001        #[test]
1002        fn instanceof_compound() -> AResult {
1003            macro_once! {
1004                // * 🚩模式:词项字符串 ⇒ 预期
1005                macro instanceof_compound($( $s:literal => $expected:expr )*) {
1006                    asserts! {$(
1007                        term!($s).instanceof_compound() => $expected,
1008                    )*}
1009                }
1010                // 占位符
1011                "_" => false
1012                // 原子词项
1013                "A" => false
1014                "$A" => false
1015                "#A" => false
1016                "?A" => false
1017                // 复合词项
1018                "{A}" => true
1019                "[A]" => true
1020                "(&, A, B)" => true // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1021                "(|, A, B)" => true
1022                "(-, A, B)" => true
1023                "(~, A, B)" => true
1024                "(*, A)" => true
1025                "(/, R, _)" => true
1026                r"(\, R, _)" => true
1027                 "(&&, A, B)" => true
1028                 "(||, A, B)" => true
1029                 "(--, A)" => true
1030                // 陈述
1031                "<A --> B>" => true
1032                "<A <-> B>" => true
1033                "<A ==> B>" => true
1034                "<A <=> B>" => true
1035            }
1036            ok!()
1037        }
1038
1039        #[test]
1040        fn is_commutative() -> AResult {
1041            macro_once! {
1042                // * 🚩模式:词项字符串 ⇒ 预期
1043                macro is_commutative($( $s:literal => $expected:expr )*) {
1044                    asserts! {$(
1045                        term!($s).is_commutative() => $expected,
1046                    )*}
1047                }
1048                // 占位符
1049                "_" => false
1050                // 原子词项
1051                "A" => false
1052                "$A" => false
1053                "#A" => false
1054                "?A" => false
1055                // 复合词项
1056                "{A}" => true
1057                "[A]" => true
1058                "(&, A, B)" => true // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1059                "(|, A, B)" => true
1060                "(-, A, B)" => false
1061                "(~, A, B)" => false
1062                "(*, A)" => false
1063                "(/, R, _)" => false
1064               r"(\, R, _)" => false
1065                "(&&, A, B)" => true
1066                "(||, A, B)" => true
1067                "(--, A)" => false
1068                // 陈述
1069                "<A --> B>" => false
1070                "<A <-> B>" => true
1071                "<A ==> B>" => false
1072                "<A <=> B>" => true
1073            }
1074            ok!()
1075        }
1076    }
1077
1078    /// 复合词项不可变引用
1079    mod compound_term_ref {
1080        use super::*;
1081
1082        #[test]
1083        fn deref() -> AResult {
1084            /// 通用测试函数
1085            fn test(term: Term) {
1086                // * 🚩首先是一个复合词项
1087                assert!(term.is_compound());
1088                // * 🚩无检查转换到复合词项(不可变引用)
1089                let compound = unsafe { term.as_compound_unchecked() };
1090                // * 🚩像一个普通的词项(不可变引用)使用
1091                dbg!(compound.identifier(), compound.components());
1092
1093                // * 🚩安全:可被多次共用
1094                let c1 = compound; // ! Copy特征无需显式clone
1095                let c2 = compound.as_compound().unwrap();
1096                let c3 = term.as_compound().unwrap();
1097                dbg!(c1, c2, c3); // 同时出现
1098
1099                // * 🚩其它系列特性
1100                asserts! {
1101                    compound.is_compound(),
1102                    compound.as_compound() => Some(compound),
1103                    // * 📌还可以使用:因为CompoundTermRef实现了Copy特征
1104                    *compound => term, // ! 这毕竟是引用,需要解引用才能
1105                    compound.clone() => compound, // ! 引用的复制≠自身的复制
1106                    (*compound).clone() => term, // ! 解引用后复制,结果才相等
1107                }
1108            }
1109            macro_once! {
1110                // * 🚩模式:词项字符串 ⇒ 预期
1111                macro test($( $term:literal )*) {$(
1112                    test(term!($term));
1113                )*}
1114                // // 占位符
1115                // "_" => 0
1116                // // 原子词项
1117                // "A" => 0
1118                // "$A" => 0
1119                // "#A" => 0
1120                // "?A" => 0
1121                // 复合词项
1122                "{A}"
1123                "[A]"
1124                "(&, A, B)" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1125                "(|, A, B)"
1126                "(-, A, B)"
1127                "(~, A, B)"
1128                "(*, A, B, C)"
1129                "(/, R, _)"
1130                r"(\, R, _)"
1131                 "(&&, A, B)"
1132                 "(||, A, B)"
1133                 "(--, A)"
1134                // 陈述
1135                "<A --> B>"
1136                "<A <-> B>"
1137                "<A ==> B>"
1138                "<A <=> B>"
1139            }
1140            ok!()
1141        }
1142
1143        #[test]
1144        fn size() -> AResult {
1145            macro_once! {
1146                // * 🚩模式:词项字符串 ⇒ 预期
1147                macro size($( $s:literal => $expected:expr )*) {
1148                    asserts! {$(
1149                        compound!($s).size() => $expected,
1150                    )*}
1151                }
1152                // // 占位符
1153                // "_" => 0
1154                // // 原子词项
1155                // "A" => 0
1156                // "$A" => 0
1157                // "#A" => 0
1158                // "?A" => 0
1159                // 复合词项
1160                "{A}" => 1
1161                "[A]" => 1
1162                "(&, A, B)" => 2 // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1163                "(|, A, B)" => 2
1164                "(-, A, B)" => 2
1165                "(~, A, B)" => 2
1166                "(*, A, B, C)" => 3
1167                "(/, R, _)" => 2 // * ⚠️算入占位符
1168                r"(\, R, _)" => 2
1169                 "(&&, A, B)" => 2
1170                 "(||, A, B)" => 2
1171                 "(--, A)" => 1
1172                // 陈述
1173                "<A --> B>" => 2
1174                "<A <-> B>" => 2
1175                "<A ==> B>" => 2
1176                "<A <=> B>" => 2
1177            }
1178            ok!()
1179        }
1180
1181        #[test]
1182        fn component_at() -> AResult {
1183            // 命中
1184            macro_once! {
1185                // * 🚩模式:词项字符串[索引] ⇒ 预期词项
1186                macro component_at($( $s:literal [ $index:expr ] => $expected:expr )*) {
1187                    asserts! {$(
1188                        compound!($s).component_at($index) => Some(&term!($expected)),
1189                    )*}
1190                }
1191                // 复合词项
1192                "{A}"[0] => "A"
1193                "[A]"[0] => "A"
1194                "(&, A, B)"[0] => "A" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1195                "(|, A, B)"[0] => "A"
1196                "(-, A, B)"[1] => "B"
1197                "(~, A, B)"[1] => "B"
1198                "(*, A, B, C)"[2] => "C"
1199                "(/, R, _)"[0] => "R" // * ⚠️算入占位符
1200                r"(\, R, _)"[0] => "R"
1201                "(/, R, _)"[1] => "_" // * ⚠️算入占位符
1202                r"(\, R, _)"[1] => "_"
1203                 "(&&, A, B)"[0] => "A"
1204                 "(||, A, B)"[0] => "A"
1205                 "(--, A)"[0] => "A"
1206                // 陈述
1207                "<A --> B>"[0] => "A"
1208                "<A <-> B>"[0] => "A"
1209                "<A ==> B>"[0] => "A"
1210                "<A <=> B>"[0] => "A"
1211            }
1212            // 未命中
1213            macro_once! {
1214                // * 🚩模式:词项字符串[索引]
1215                macro component_at($( $s:literal [ $index:expr ] )*) {
1216                    asserts! {$(
1217                        compound!($s).component_at($index) => None,
1218                    )*}
1219                }
1220                // // 占位符
1221                // "_"[0]
1222                // // 原子词项
1223                // "A"[0]
1224                // "$A"[0]
1225                // "#A"[0]
1226                // "?A"[0]
1227                // 复合词项
1228                "{A}"[1]
1229                "[A]"[1]
1230                "(&, A, B)"[2] // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1231                "(|, A, B)"[2]
1232                "(-, A, B)"[2]
1233                "(~, A, B)"[2]
1234                "(*, A, B, C)"[3]
1235                "(/, R, _)"[2] // * ⚠️算入占位符
1236                r"(\, R, _)"[2]
1237                 "(&&, A, B)"[2]
1238                 "(||, A, B)"[2]
1239                 "(--, A)"[1]
1240                // 陈述
1241                "<A --> B>"[2]
1242                "<A <-> B>"[2]
1243                "<A ==> B>"[2]
1244                "<A <=> B>"[2]
1245            }
1246            ok!()
1247        }
1248
1249        #[test]
1250        fn component_at_unchecked() -> AResult {
1251            // 命中
1252            macro_once! {
1253                // * 🚩模式:词项字符串[索引] ⇒ 预期词项
1254                macro component_at_unchecked($( $s:literal [ $index:expr ] => $expected:expr )*) {
1255                    unsafe {
1256                        asserts! {$(
1257                            compound!($s).component_at_unchecked($index) => &term!($expected),
1258                        )*}
1259                    }
1260                }
1261                // 复合词项
1262                "{A}"[0] => "A"
1263                "[A]"[0] => "A"
1264                "(&, A, B)"[0] => "A" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1265                "(|, A, B)"[0] => "A"
1266                "(-, A, B)"[1] => "B"
1267                "(~, A, B)"[1] => "B"
1268                "(*, A, B, C)"[2] => "C"
1269                "(/, R, _)"[0] => "R" // ! 不算占位符
1270                r"(\, R, _)"[0] => "R"
1271                 "(&&, A, B)"[0] => "A"
1272                 "(||, A, B)"[0] => "A"
1273                 "(--, A)"[0] => "A"
1274                // 陈述
1275                "<A --> B>"[0] => "A"
1276                "<A <-> B>"[0] => "A"
1277                "<A ==> B>"[0] => "A"
1278                "<A <=> B>"[0] => "A"
1279            }
1280            ok!()
1281        }
1282
1283        // * ✅`get_components`已在[`TermComponents::iter`]中测试
1284
1285        #[test]
1286        fn clone_components() -> AResult {
1287            macro_once! {
1288                // * 🚩模式:词项字符串 | 复制之后与新词项的「组分」相等
1289                macro clone_components($($s:literal)*) {
1290                    asserts! {$(
1291                        // * 🚩假设其拷贝的词项与迭代器收集的相等
1292                        compound!($s).clone_components() => term!($s).components().iter().cloned().collect::<Vec<_>>(),
1293                    )*}
1294                }
1295                // // 占位符
1296                // "_"
1297                // // 原子词项
1298                // "A"
1299                // "$A"
1300                // "#A"
1301                // "?A"
1302                // 复合词项
1303                "{A}"
1304                "[A]"
1305                "(&, A, B)" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1306                "(|, A, B)"
1307                "(-, A, B)"
1308                "(~, A, B)"
1309                "(*, A)"
1310                "(/, R, _)"
1311                r"(\, R, _)"
1312                 "(&&, A, B)"
1313                 "(||, A, B)"
1314                 "(--, A)"
1315                // 陈述
1316                "<A --> B>"
1317                "<A <-> B>"
1318                "<A ==> B>"
1319                "<A <=> B>"
1320            }
1321            ok!()
1322        }
1323
1324        #[test]
1325        fn contain_component() -> AResult {
1326            macro_once! {
1327                // * 🚩模式:词项 in 容器词项
1328                macro contain_component($($term:literal in $container:expr)*) {
1329                    asserts! {$(
1330                        compound!($container).contain_component(&term!($term))
1331                    )*}
1332                }
1333                // 复合词项
1334                "A" in "{A}"
1335                "A" in "[A]"
1336                "A" in "(&, A, B)" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1337                "A" in "(|, A, B)"
1338                "A" in "(-, A, B)"
1339                "A" in "(~, A, B)"
1340                "B" in "(-, A, B)"
1341                "B" in "(~, A, B)"
1342                "A" in "(*, A)"
1343                "R" in  "(/, R, _)"
1344                "R" in r"(\, R, _)"
1345                "_" in  "(/, R, _)" // ! 📌【2024-06-14 13:46:19】现在「占位符」也包含在内
1346                "_" in r"(\, R, _)" // ! 📌【2024-06-14 13:46:19】现在「占位符」也包含在内
1347                "A" in  "(&&, A, B)"
1348                "A" in  "(||, A, B)"
1349                "A" in  "(--, A)"
1350                // 陈述
1351                "A" in "<A --> B>"
1352                "A" in "<A <-> B>"
1353                "A" in "<A ==> B>"
1354                "A" in "<A <=> B>"
1355                "B" in "<A --> B>"
1356                "B" in "<A <-> B>"
1357                "B" in "<A ==> B>"
1358                "B" in "<A <=> B>"
1359            }
1360            macro_once! {
1361                // * 🚩模式:词项 in 容器词项
1362                macro contain_component($($term:literal !in $container:expr)*) {
1363                    asserts! {$(
1364                        !compound!($container).contain_component(&term!($term))
1365                    )*}
1366                }
1367                // 复合词项
1368                "X" !in "{A}"
1369                "X" !in "[A]"
1370                "X" !in "(&, A, B)" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
1371                "X" !in "(|, A, B)"
1372                "X" !in "(-, A, B)"
1373                "X" !in "(~, A, B)"
1374                "X" !in "(*, A)"
1375                "X" !in "(/, R, _)"
1376                "X" !in r"(\, R, _)"
1377                "X" !in  "(&&, A, B)"
1378                "X" !in  "(||, A, B)"
1379                "X" !in  "(--, A)"
1380                // 陈述
1381                "C" !in "<A --> B>"
1382                "C" !in "<A <-> B>"
1383                "C" !in "<A ==> B>"
1384                "C" !in "<A <=> B>"
1385            }
1386            ok!()
1387        }
1388
1389        #[test]
1390        fn contain_term() -> AResult {
1391            macro_once! {
1392                // * 🚩模式:词项 in 容器词项
1393                macro contain_term($($term:literal in $container:expr)*) {
1394                    asserts! {$(
1395                        compound!($container).contain_term(&term!($term))
1396                    )*}
1397                }
1398                // 复合词项
1399                "A" in "{{{{{{A}}}}}}"
1400                "A" in "[[[[[[A]]]]]]"
1401                "A" in "(&, (&, (&, (&, (&, A, B), B), B), B), B)"
1402                "A" in "(|, (|, (|, (|, (|, A, B), B), B), B), B)"
1403                "A" in "(-, (-, A, a), (-, B, b))"
1404                "A" in "(~, (~, A, a), (~, B, b))"
1405                "B" in "(-, (-, A, a), (-, B, b))"
1406                "B" in "(~, (~, A, a), (~, B, b))"
1407                "A" in "(*, (*, (*, (*, (*, A)))))"
1408                "R" in  "(/, (/, (/, (/, (/, R, _), _), _), _), _)"
1409                "R" in r"(\, (\, (\, (\, (\, R, _), _), _), _), _)"
1410                "A" in  "(&&, (&&, (&&, (&&, (&&, A, B), B), B), B), B)"
1411                "A" in  "(||, (||, (||, (||, (||, A, B), B), B), B), B)"
1412                "A" in  "(--, (--, (--, (--, (--, A)))))"
1413                // 陈述
1414                "A" in "<<A --> a> --> <B ==> b>>"
1415                "B" in "<<A --> a> --> <B ==> b>>"
1416                "A" in "<<A <-> a> <-> <B <=> b>>"
1417                "B" in "<<A <-> a> <-> <B <=> b>>"
1418                "A" in "<<A --> a> ==> <B ==> b>>"
1419                "B" in "<<A --> a> ==> <B ==> b>>"
1420                "A" in "<<A <-> a> <=> <B <=> b>>"
1421                "B" in "<<A <-> a> <=> <B <=> b>>"
1422            }
1423            macro_once! {
1424                // * 🚩模式:词项 in 容器词项
1425                macro contain_term($($term:literal !in $container:expr)*) {
1426                    asserts! {$(
1427                        !compound!($container).contain_term(&term!($term))
1428                    )*}
1429                }
1430                // 复合词项
1431                "X" !in "{{{{{{A}}}}}}"
1432                "X" !in "[[[[[[A]]]]]]"
1433                "X" !in "(&, (&, (&, (&, (&, A, B), B), B), B), B)"
1434                "X" !in "(|, (|, (|, (|, (|, A, B), B), B), B), B)"
1435                "X" !in "(-, (-, A, a), (-, B, b))"
1436                "X" !in "(~, (~, A, a), (~, B, b))"
1437                "X" !in "(*, (*, (*, (*, (*, A)))))"
1438                "X" !in  "(/, (/, (/, (/, (/, R, _), _), _), _), _)"
1439                "X" !in r"(\, (\, (\, (\, (\, R, _), _), _), _), _)"
1440                "X" !in  "(&&, (&&, (&&, (&&, (&&, A, B), B), B), B), B)"
1441                "X" !in  "(||, (||, (||, (||, (||, A, B), B), B), B), B)"
1442                "X" !in  "(--, (--, (--, (--, (--, A)))))"
1443                // 陈述
1444                "X" !in "<<A --> a> --> <B ==> b>>"
1445                "X" !in "<<A --> a> --> <B ==> b>>"
1446                "X" !in "<<A <-> a> <-> <B <=> b>>"
1447                "X" !in "<<A <-> a> <-> <B <=> b>>"
1448            }
1449            ok!()
1450        }
1451
1452        #[test]
1453        fn contain_all_components() -> AResult {
1454            macro_once! {
1455                // * 🚩模式:词项 in 容器词项
1456                macro test($($term:literal in $container:expr)*) {
1457                    asserts! {$(
1458                        compound!($container).contain_all_components(&term!($term))
1459                    )*}
1460                }
1461                // 复合词项
1462                "A" in "{A}"
1463                "{A}" in "{A}"
1464                "{A}" in "{A, B}"
1465                "{A}" in "{A, B, C}"
1466                "{B}" in "{A, B, C}"
1467                "{C}" in "{A, B, C}"
1468                "{A, B}" in "{A, B, C}"
1469                "{A, C}" in "{A, B, C}"
1470                "{B, C}" in "{A, B, C}"
1471                "{A, B, C}" in "{A, B, C}"
1472                "A" in "(-, A, B)"
1473                "B" in "(-, A, B)"
1474                "(-, A, B)" in "(-, A, B)"
1475                "A" in "(*, A, B, C, D, E)"
1476                "(*, A)" in "(*, A, B, C, D, E)"
1477                "(*, A, B)" in "(*, A, B, C, D, E)"
1478                "(*, E, B)" in "(*, A, B, C, D, E)"
1479                "(*, E, A)" in "(*, A, B, C, D, E)"
1480                "R" in  "(/, R, _)"
1481                "_" in  "(/, R, _)"
1482                "R" in  "(/, R, _, (*, A))"
1483                "_" in  "(/, R, _, (*, A))"
1484                "(*, A)" in  "(/, R, _, (*, A))"
1485                "(/, R, _)" in  "(/, R, _, (*, A))"
1486                "R" in r"(\, R, _)"
1487                "_" in r"(\, R, _)"
1488                "R" in r"(\, R, _, (*, A))"
1489                "_" in r"(\, R, _, (*, A))"
1490                "(*, A)" in r"(\, R, _, (*, A))"
1491                r"(\, R, _)" in r"(\, R, _, (*, A))"
1492                // 陈述
1493                "A" in "<A --> B>"
1494                "B" in "<A --> B>"
1495                "<A --> B>" in "<A --> B>"
1496                "<B --> A>" in "<A --> B>"
1497                "A" in "<A <-> B>"
1498                "B" in "<A <-> B>"
1499                "<A <-> B>" in "<A <-> B>"
1500                "<B <-> A>" in "<A <-> B>"
1501                "A" in "<A ==> B>"
1502                "B" in "<A ==> B>"
1503                "<A ==> B>" in "<A ==> B>"
1504                "<B ==> A>" in "<A ==> B>"
1505                "A" in "<A <=> B>"
1506                "B" in "<A <=> B>"
1507                "<A <=> B>" in "<A <=> B>"
1508                "<B <=> A>" in "<A <=> B>"
1509            }
1510            ok!()
1511        }
1512
1513        #[test]
1514        fn can_extract() -> AResult {
1515            fn test(term: Term, expected: bool) {
1516                let compound = term.as_compound().unwrap();
1517                assert_eq!(compound.can_extract_to_inner(), expected);
1518            }
1519            macro_once! {
1520                // * 🚩模式:词项字符串⇒预期
1521                macro test($($term:expr => $expected:expr)*) {
1522                    $( test(term!($term), $expected); )*
1523                }
1524                // * 🚩正例
1525                "(&&, A, B)" => true
1526                "(||, A, B)" => true
1527                "(&, A, B)" => true
1528                "(|, A, B)" => true
1529                "(-, A, B)" => true
1530                "(~, A, B)" => true
1531                // * 🚩反例
1532                "{A}" => false
1533                "[A]" => false
1534            }
1535            ok!()
1536        }
1537
1538        #[test]
1539        fn reduce_components() -> AResult {
1540            /// ! 📝【2024-06-18 23:56:37】教训:不要在宏展开里头写过程式代码
1541            /// * * ℹ️宏展开里头的代码,每个都是实实在在要「一个个铺开」被编译器看到的
1542            /// * * ⚠️若直接在里头写过程式代码,即便代码只有十多行,但若有成百上千个测试用例,则代码行数会成倍增长
1543            /// * * 💥过多的代码行数,编译器就会爆炸
1544            fn test(compound_str: &str, term_str: &str, expected: Option<Term>) {
1545                // * 🚩解析词项(解析失败则报警返回)
1546                let compound: Term = unwrap_or_return!(@compound_str.parse(), err => eprintln!("{compound_str:?}解析失败: {err}"));
1547                let term: Term = unwrap_or_return!(@term_str.parse(), err => eprintln!("{term_str:?}解析失败: {err}"));
1548                // * 🚩获取复合词项引用
1549                let compound_ref = compound.as_compound().expect("构造出来的不是复合词项");
1550                // * 🚩运行代码
1551                let out = CompoundTermRef::reduce_components(compound_ref, &term);
1552                // * 🚩检验结果
1553                assert_eq!(
1554                    out,
1555                    expected,
1556                    "{compound_str:?}, {term_str:?} => {} != {}",
1557                    format_option_term(&out),
1558                    format_option_term(&expected),
1559                );
1560            }
1561            macro_once! {
1562                // * 🚩模式:参数列表 ⇒ 预期词项
1563                macro test($($compound:tt, $term:tt => $expected:tt;)*) {
1564                    $( test($compound, $term, option_term!($expected)); )*
1565                }
1566                // * ℹ️用例均源自OpenNARS实际运行
1567                // * 📌【2024-09-07 14:39:12】对「预期的可空词项」不过滤
1568                //   * 💭若「预期的可空词项」解析失败为空,则作为参数的词项也将为空 ⇒ 测试不会在无效参数中进行
1569                //   * 📄所谓「无效词项」如下边少数注释所述
1570                //     * ⚠️注释尚不全面:仅标注了前边几个无效参数
1571                "(&&,<(&,bird,gull) --> bird>,<(&,bird,gull) --> [swimmer]>)", "<(&,bird,gull) --> [swimmer]>" => "<(&,bird,gull) --> bird>"; // ! ❌【2024-09-07 14:20:04】陈述`<(&,bird,gull) --> bird>`非法——主项包含谓项
1572                "(&&,<(&,bird,swan) --> [bird]>,<(&,bird,swan) --> [swimmer]>)", "<(&,bird,swan) --> [swimmer]>" => "<(&,bird,swan) --> [bird]>";
1573                "(&&,<(&,bird,swimmer) --> (&,animal,swimmer)>,<(&,bird,swimmer) --> (|,swan,swimmer)>)", "<(&,bird,swimmer) --> (&,animal,swimmer)>" => "<(&,bird,swimmer) --> (|,swan,swimmer)>";
1574                "(&&,<(&,chess,sport) --> chess>,<(&,chess,sport) --> competition>)", "<(&,chess,sport) --> competition>" => "<(&,chess,sport) --> chess>"; // ! ❌【2024-09-07 14:21:34】陈述`<(&,chess,sport) --> chess>`非法——主项包含谓项
1575                "(&&,<(&,key,(/,open,_,lock)) --> key>,<(&,key,(/,open,_,lock)) --> (/,open,_,{lock1})>)", "<(&,key,(/,open,_,lock)) --> (/,open,_,{lock1})>" => "<(&,key,(/,open,_,lock)) --> key>";  // ! ❌【2024-09-07 14:21:34】陈述`<(&,key,(/,open,_,lock)) --> key>`非法——主项包含谓项
1576                "(&&,<(*,0) --> (*,(/,num,_))>,<{0} --> (*,(/,num,_))>)", "<(*,0) --> (*,(/,num,_))>" => "<{0} --> (*,(/,num,_))>";
1577                "(&&,<(*,0) --> (*,{0})>,<(*,(*,0)) --> (*,{0})>)", "<(*,(*,0)) --> (*,{0})>" => "<(*,0) --> (*,{0})>";
1578                "(&&,<(*,0) --> (/,num,_)>,<(*,0) --> [num]>)", "<(*,0) --> (/,num,_)>" => "<(*,0) --> [num]>";
1579                "(&&,<(*,0) --> num>,<(/,num,_) --> num>)", "<(/,num,_) --> num>" => "<(*,0) --> num>";
1580                "(&&,<(*,0) --> num>,<{0} --> num>)", "<(*,0) --> num>" => "<{0} --> num>";
1581                "(&&,<(*,0) --> num>,<{0} --> num>)", "<{0} --> num>" => "<(*,0) --> num>";
1582                "(&&,<(*,a,b) --> like>,<(*,a,b) --> (*,a,b)>)", "<(*,a,b) --> like>" => "<(*,a,b) --> (*,a,b)>"; // ! ❌【2024-09-07 14:34:40】`<(*,a,b) --> (*,a,b)>`非法:重言式
1583                "(&&,<(*,b,a) --> [like]>,<(*,b,a) --> (*,b,(/,like,_,b))>)", "<(*,b,a) --> [like]>" => "<(*,b,a) --> (*,b,(/,like,_,b))>";
1584                "(&&,<(*,b,a) --> like>,<(*,b,a) --> (*,(/,like,b,_),b)>)", "<(*,b,a) --> like>" => "<(*,b,a) --> (*,(/,like,b,_),b)>";
1585                "(&&,<(/,(*,(/,num,_)),_) --> (/,num,_)>,<(/,(*,(/,num,_)),_) --> [num]>)", "<(/,(*,(/,num,_)),_) --> (/,num,_)>" => "<(/,(*,(/,num,_)),_) --> [num]>";
1586                "(&&,<(/,(/,REPRESENT,_,<{(*,CAT,FISH)} --> FOOD>),_,eat,fish) --> [cat]>,<(/,(/,REPRESENT,_,<{(*,CAT,FISH)} --> FOOD>),_,eat,fish) --> (&,CAT,cat)>)", "<(/,(/,REPRESENT,_,<{(*,CAT,FISH)} --> FOOD>),_,eat,fish) --> [cat]>" => "<(/,(/,REPRESENT,_,<{(*,CAT,FISH)} --> FOOD>),_,eat,fish) --> (&,CAT,cat)>";
1587                "(&&,<(/,neutralization,(/,reaction,_,base),_) --> base>,<(/,neutralization,(/,reaction,_,base),_) --> (/,reaction,(/,reaction,_,base),_)>)", "<(/,neutralization,(/,reaction,_,base),_) --> (/,reaction,(/,reaction,_,base),_)>" => "<(/,neutralization,(/,reaction,_,base),_) --> base>";
1588                "(&&,<(/,open,_,lock) --> key>,<(/,open,_,lock) --> (/,open,_,{lock1})>)", "<(/,open,_,lock) --> (/,open,_,{lock1})>" => "<(/,open,_,lock) --> key>";
1589                "(&&,<(/,open,{key1},_) --> lock>,<(/,open,{key1},_) --> (/,open,key,_)>)", "<(/,open,{key1},_) --> (/,open,key,_)>" => "<(/,open,{key1},_) --> lock>";
1590                "(&&,<(|,bird,gull) --> [bird]>,<(|,bird,gull) --> [swimmer]>)", "<(|,bird,gull) --> [swimmer]>" => "<(|,bird,gull) --> [bird]>";
1591                "(&&,<(|,robin,swan) --> (&,bird,swimmer)>,<(|,robin,swan) --> (|,bird,swimmer)>)", "<(|,robin,swan) --> (&,bird,swimmer)>" => "<(|,robin,swan) --> (|,bird,swimmer)>";
1592                "(&&,<(~,boy,girl) --> [strong]>,<(~,boy,girl) --> [[strong]]>)", "<(~,boy,girl) --> [strong]>" => "<(~,boy,girl) --> [[strong]]>";
1593                "(&&,<(~,swan,bird) --> [bird]>,<(~,swan,bird) --> [swimmer]>)", "<(~,swan,bird) --> [swimmer]>" => "<(~,swan,bird) --> [bird]>";
1594                "(&&,<0 --> num>,<0 --> {0}>)", "<0 --> num>" => "<0 --> {0}>";
1595                "(&&,<?1 --> animal>,<?1 --> [swimmer]>)", "<?1 --> [swimmer]>" => "<?1 --> animal>";
1596                "(&&,<CAT --> CAT>,<cat --> CAT>)", "<cat --> CAT>" => "<CAT --> CAT>";
1597                "(&&,<[[smart]] --> [bright]>,<[[smart]] --> [[bright]]>)", "<[[smart]] --> [[bright]]>" => "<[[smart]] --> [bright]>";
1598                "(&&,<acid --> (/,reaction,_,base)>,<(/,neutralization,_,base) --> (/,reaction,_,base)>)", "<acid --> (/,reaction,_,base)>" => "<(/,neutralization,_,base) --> (/,reaction,_,base)>";
1599                "(&&,<animal --> (&,bird,swimmer)>,<animal --> (|,bird,swimmer)>)", "<animal --> (|,bird,swimmer)>" => "<animal --> (&,bird,swimmer)>";
1600                "(&&,<animal --> [bird]>,<animal --> (|,bird,swimmer)>)", "<animal --> (|,bird,swimmer)>" => "<animal --> [bird]>";
1601                "(&&,<animal <-> robin>,<robin <-> [flying]>)", "<animal <-> robin>" => "<robin <-> [flying]>";
1602                "(&&,<animal <-> robin>,<robin <-> [flying]>)", "<robin <-> [flying]>" => "<animal <-> robin>";
1603                "(&&,<animal <-> robin>,<robin <-> [flying]>)", "[flying]" => None;
1604                "(&&,<animal <-> robin>,<robin <-> [flying]>)", "animal" => None;
1605                "(&&,<bird --> (|,robin,swimmer)>,<gull --> (|,robin,swimmer)>)", "<gull --> (|,robin,swimmer)>" => "<bird --> (|,robin,swimmer)>";
1606                "(&&,<bird --> [bird]>,<{Tweety} --> [bird]>)", "<{Tweety} --> [bird]>" => "<bird --> [bird]>";
1607                "(&&,<bird --> [with_wings]>,<bird --> [[with_wings]]>)", "<bird --> [with_wings]>" => "<bird --> [[with_wings]]>";
1608                "(&&,<bird --> animal>,<bird --> [swimmer]>)", "<bird --> [swimmer]>" => "<bird --> animal>";
1609                "(&&,<bird --> flyer>,<bird --> {Birdie}>)", "<bird --> {Birdie}>" => "<bird --> flyer>";
1610                "(&&,<bird --> flyer>,<{Tweety} --> flyer>)", "<{Tweety} --> flyer>" => "<bird --> flyer>";
1611                "(&&,<bird --> {Birdie}>,<{Tweety} --> {Birdie}>)", "<{Tweety} --> {Birdie}>" => "<bird --> {Birdie}>";
1612                "(&&,<cat --> [CAT]>,<cat --> (|,CAT,(/,(/,REPRESENT,_,<{(*,CAT,FISH)} --> FOOD>),_,eat,fish))>)", "<cat --> [CAT]>" => "<cat --> (|,CAT,(/,(/,REPRESENT,_,<{(*,CAT,FISH)} --> FOOD>),_,eat,fish))>";
1613                "(&&,<cat --> cat>,<cat --> (/,(/,REPRESENT,_,<(*,CAT,FISH) --> FOOD>),_,eat,fish)>)", "<cat --> (/,(/,REPRESENT,_,<(*,CAT,FISH) --> FOOD>),_,eat,fish)>" => "<cat --> cat>";
1614                "(&&,<chess --> [competition]>,<sport --> [competition]>)", "<sport --> [competition]>" => "<chess --> [competition]>";
1615                "(&&,<flyer --> (|,bird,[yellow])>,<{Tweety} --> (|,bird,[yellow])>)", "<{Tweety} --> (|,bird,[yellow])>" => "<flyer --> (|,bird,[yellow])>";
1616                "(&&,<gull --> [bird]>,<gull --> (&,bird,swimmer)>)", "<gull --> [bird]>" => "<gull --> (&,bird,swimmer)>";
1617                "(&&,<key --> (/,open,_,lock1)>,<(/,open,_,lock) --> (/,open,_,lock1)>)", "<(/,open,_,lock) --> (/,open,_,lock1)>" => "<key --> (/,open,_,lock1)>";
1618                "(&&,<key --> (/,open,_,{lock1})>,<{key1} --> (/,open,_,{lock1})>)", "<key --> (/,open,_,{lock1})>" => "<{key1} --> (/,open,_,{lock1})>";
1619                "(&&,<key --> (/,open,_,{lock1})>,<{key1} --> (/,open,_,{lock1})>)", "<{key1} --> (/,open,_,{lock1})>" => "<key --> (/,open,_,{lock1})>";
1620                "(&&,<key --> (|,key,(/,open,_,{lock1}))>,<{{key1}} --> (|,key,(/,open,_,{lock1}))>)", "<{{key1}} --> (|,key,(/,open,_,{lock1}))>" => "<key --> (|,key,(/,open,_,{lock1}))>";
1621                "(&&,<key --> [key]>,<{{key1}} --> [key]>)", "<{{key1}} --> [key]>" => "<key --> [key]>";
1622                "(&&,<key --> key>,<key --> (/,open,_,{lock1})>)", "<key --> (/,open,_,{lock1})>" => "<key --> key>";
1623                "(&&,<key --> key>,<{{key1}} --> key>)", "<{{key1}} --> key>" => "<key --> key>";
1624                "(&&,<key --> {key1}>,<{{key1}} --> {key1}>)", "<key --> {key1}>" => "<{{key1}} --> {key1}>";
1625                "(&&,<lock --> lock>,<lock --> (/,open,{key1},_)>)", "<lock --> (/,open,{key1},_)>" => "<lock --> lock>";
1626                "(&&,<lock1 --> (/,open,{key1},_)>,<{key1} --> key>)", "<lock1 --> (/,open,{key1},_)>" => "<{key1} --> key>";
1627                "(&&,<lock1 --> (/,open,{key1},_)>,<{key1} --> key>)", "<{key1} --> key>" => "<lock1 --> (/,open,{key1},_)>";
1628                "(&&,<lock1 --> (/,open,{key1},_)>,<{{key1}} --> key>)", "<lock1 --> (/,open,{key1},_)>" => "<{{key1}} --> key>";
1629                "(&&,<lock1 --> [lock]>,<lock1 --> [(/,open,{key1},_)]>)", "<lock1 --> [(/,open,{key1},_)]>" => "<lock1 --> [lock]>";
1630                "(&&,<lock1 --> [lock]>,<lock1 --> [(/,open,{key1},_)]>)", "<lock1 --> [lock]>" => "<lock1 --> [(/,open,{key1},_)]>";
1631                "(&&,<neutralization --> (*,acid,(/,reaction,acid,_))>,<(*,(/,neutralization,_,base),base) --> (*,acid,(/,reaction,acid,_))>)", "<(*,(/,neutralization,_,base),base) --> (*,acid,(/,reaction,acid,_))>" => "<neutralization --> (*,acid,(/,reaction,acid,_))>";
1632                "(&&,<neutralization --> neutralization>,<(*,acid,base) --> neutralization>)", "<(*,acid,base) --> neutralization>" => "<neutralization --> neutralization>";
1633                "(&&,<neutralization --> reaction>,<neutralization --> (*,(/,reaction,_,base),base)>)", "<neutralization --> (*,(/,reaction,_,base),base)>" => "<neutralization --> reaction>";
1634                "(&&,<neutralization --> reaction>,<neutralization --> (*,(/,reaction,_,base),base)>)", "<neutralization --> reaction>" => "<neutralization --> (*,(/,reaction,_,base),base)>";
1635                "(&&,<neutralization --> reaction>,<neutralization --> (*,acid,base)>)", "<neutralization --> (*,acid,base)>" => "<neutralization --> reaction>";
1636                "(&&,<robin --> (&,animal,(|,swimmer,(-,animal,swan)))>,<{bird} --> (&,animal,(|,swimmer,(-,animal,swan)))>)", "<{bird} --> (&,animal,(|,swimmer,(-,animal,swan)))>" => "<robin --> (&,animal,(|,swimmer,(-,animal,swan)))>";
1637                "(&&,<robin --> (&,animal,swimmer)>,<robin --> (|,swan,swimmer)>)", "<robin --> (&,animal,swimmer)>" => "<robin --> (|,swan,swimmer)>";
1638                "(&&,<robin --> (&,bird,[yellow])>,<{Tweety} --> (&,bird,[yellow])>)", "<{Tweety} --> (&,bird,[yellow])>" => "<robin --> (&,bird,[yellow])>";
1639                "(&&,<robin --> (&,bird,swimmer)>,<robin --> (-,bird,swimmer)>)", "<robin --> (-,bird,swimmer)>" => "<robin --> (&,bird,swimmer)>";
1640                "(&&,<robin --> (&,swimmer,(-,animal,swan))>,<{bird} --> (&,swimmer,(-,animal,swan))>)", "<{bird} --> (&,swimmer,(-,animal,swan))>" => "<robin --> (&,swimmer,(-,animal,swan))>";
1641                "(&&,<robin --> (-,animal,swan)>,<{bird} --> (-,animal,swan)>)", "<{bird} --> (-,animal,swan)>" => "<robin --> (-,animal,swan)>";
1642                "(&&,<robin --> (|,swan,swimmer)>,<{bird} --> (|,swan,swimmer)>)", "<{bird} --> (|,swan,swimmer)>" => "<robin --> (|,swan,swimmer)>";
1643                "(&&,<robin --> (|,swimmer,(-,animal,swan))>,<{robin} --> (|,swimmer,(-,animal,swan))>)", "robin" => None;
1644                "(&&,<robin --> [[chirping]]>,<robin --> [[flying]]>)", "robin" => None;
1645                "(&&,<robin --> [[chirping]]>,<robin --> [[flying]]>,<robin --> [[living]]>)", "<robin --> [[flying]]>" => "(&&,<robin --> [[chirping]]>,<robin --> [[living]]>)";
1646                "(&&,<robin --> [[chirping]]>,<robin --> [[flying]]>,<robin --> [[living]]>)", "robin" => None;
1647                "(&&,<robin --> [[flying]]>,<robin --> [[with_wings]]>)", "<robin --> [[flying]]>" => "<robin --> [[with_wings]]>";
1648                "(&&,<robin --> [[flying]]>,<robin --> [[with_wings]]>)", "<robin --> [bird]>" => None;
1649                "(&&,<robin --> [[with_wings]]>,(||,<robin --> [bird]>,<robin --> [[flying]]>))", "robin" => None;
1650                "(&&,<robin --> [animal]>,<robin --> [[flying]]>)", "<robin --> [[flying]]>" => "<robin --> [animal]>";
1651                "(&&,<robin --> [animal]>,<robin --> [[flying]]>)", "robin" => None;
1652                "(&&,<robin --> [animal]>,<robin --> [bird]>)", "robin" => None;
1653                "(&&,<robin --> [bird]>,<robin --> (&,bird,swimmer)>)", "<robin --> (&,bird,swimmer)>" => "<robin --> [bird]>";
1654                "(&&,<robin --> [bird]>,<robin --> [[flying]]>)", "<robin --> [[with_wings]]>" => None;
1655                "(&&,<robin --> [chirping]>,(||,<robin --> bird>,<robin --> flyer>))", "(||,<robin --> bird>,<robin --> flyer>)" => "<robin --> [chirping]>";
1656                "(&&,<robin --> [chirping]>,(||,<robin --> bird>,<robin --> flyer>))", "<robin --> [chirping]>" => "(||,<robin --> bird>,<robin --> flyer>)";
1657                "(&&,<robin --> [chirping]>,(||,<robin --> bird>,<robin --> flyer>))", "<robin --> flyer>" => None;
1658                "(&&,<robin --> [chirping]>,(||,<robin --> bird>,<robin --> flyer>))", "[chirping]" => None;
1659                "(&&,<robin --> [chirping]>,(||,<robin --> bird>,<robin --> flyer>))", "robin" => None;
1660                "(&&,<robin --> [chirping]>,<robin --> [flying]>)", "[chirping]" => None;
1661                "(&&,<robin --> [chirping]>,<robin --> [flying]>,(||,<robin --> bird>,<robin --> flyer>))", "(||,<robin --> bird>,<robin --> flyer>)" => "(&&,<robin --> [chirping]>,<robin --> [flying]>)";
1662                "(&&,<robin --> [chirping]>,<robin --> [flying]>,(||,<robin --> bird>,<robin --> flyer>))", "<robin --> [chirping]>" => "(&&,<robin --> [flying]>,(||,<robin --> bird>,<robin --> flyer>))";
1663                "(&&,<robin --> [chirping]>,<robin --> [flying]>,(||,<robin --> bird>,<robin --> flyer>))", "<robin --> bird>" => None;
1664                "(&&,<robin --> [chirping]>,<robin --> [flying]>,(||,<robin --> bird>,<robin --> flyer>))", "[chirping]" => None;
1665                "(&&,<robin --> [chirping]>,<robin --> [flying]>,(||,<robin --> bird>,<robin --> flyer>))", "robin" => None;
1666                "(&&,<robin --> [chirping]>,<robin --> [flying]>,<robin --> [living]>)", "<robin --> [flying]>" => "(&&,<robin --> [chirping]>,<robin --> [living]>)";
1667                "(&&,<robin --> [chirping]>,<robin --> [flying]>,<robin --> [living]>)", "[chirping]" => None;
1668                "(&&,<robin --> [chirping]>,<robin --> [flying]>,<robin --> [living]>)", "robin" => None;
1669                "(&&,<robin --> [chirping]>,<robin --> {Birdie}>)", "<robin --> {Birdie}>" => "<robin --> [chirping]>";
1670                "(&&,<robin --> [chirping]>,<robin --> {Birdie}>)", "[chirping]" => None;
1671                "(&&,<robin --> [chirping]>,<robin --> {Birdie}>)", "robin" => None;
1672                "(&&,<robin --> [chirping]>,<robin --> {Birdie}>)", "{Birdie}" => None;
1673                "(&&,<robin --> [flyer]>,<robin --> [[flying]]>)", "<robin --> [bird]>" => None;
1674                "(&&,<robin --> animal>,<robin --> [flying]>)", "<robin --> animal>" => "<robin --> [flying]>";
1675                "(&&,<robin --> animal>,<robin --> [flying]>)", "[flying]" => None;
1676                "(&&,<robin --> animal>,<robin --> [flying]>)", "animal" => None;
1677                "(&&,<robin --> flyer>,<(*,robin,worms) --> food>)", "flyer" => None;
1678                "(&&,<robin <-> [chirping]>,<robin <-> [flying]>)", "<robin <-> [chirping]>" => "<robin <-> [flying]>";
1679                "(&&,<robin <-> [chirping]>,<robin <-> [flying]>)", "[chirping]" => None;
1680                "(&&,<robin <-> [chirping]>,<robin <-> [flying]>)", "robin" => None;
1681                "(&&,<robin <-> [chirping]>,<robin <-> [flying]>,<robin <-> [with_wings]>)", "<robin <-> [with_wings]>" => "(&&,<robin <-> [chirping]>,<robin <-> [flying]>)";
1682                "(&&,<robin <-> [chirping]>,<robin <-> [flying]>,<robin <-> [with_wings]>)", "[chirping]" => None;
1683                "(&&,<robin <-> [chirping]>,<robin <-> [flying]>,<robin <-> [with_wings]>)", "robin" => None;
1684                "(&&,<robin <=> swimmer>,<robin <=> [flying]>)", "<robin <=> [flying]>" => "<robin <=> swimmer>";
1685                "(&&,<robin <=> swimmer>,<robin <=> [flying]>)", "<robin <=> swimmer>" => "<robin <=> [flying]>";
1686                "(&&,<robin <=> swimmer>,<robin <=> [flying]>)", "[flying]" => None;
1687                "(&&,<robin <=> swimmer>,<robin <=> [flying]>)", "robin" => None;
1688                "(&&,<robin ==> [flying]>,<robin ==> [with_wings]>)", "<robin ==> [flying]>" => "<robin ==> [with_wings]>";
1689                "(&&,<robin ==> [flying]>,<robin ==> [with_wings]>)", "[flying]" => None;
1690                "(&&,<robin ==> [flying]>,<robin ==> [with_wings]>)", "robin" => None;
1691                "(&&,<robin ==> swimmer>,<robin ==> [flying]>)", "<robin ==> [flying]>" => "<robin ==> swimmer>";
1692                "(&&,<robin ==> swimmer>,<robin ==> [flying]>)", "<robin ==> swimmer>" => "<robin ==> [flying]>";
1693                "(&&,<robin ==> swimmer>,<robin ==> [flying]>)", "[flying]" => None;
1694                "(&&,<robin ==> swimmer>,<robin ==> [flying]>)", "robin" => None;
1695                "(&&,<soda --> [(/,reaction,acid,_)]>,<{base} --> [(/,reaction,acid,_)]>)", "<{base} --> [(/,reaction,acid,_)]>" => "<soda --> [(/,reaction,acid,_)]>";
1696                "(&&,<sport --> competition>,<(&,chess,(|,chess,sport)) --> competition>)", "<(&,chess,(|,chess,sport)) --> competition>" => "<sport --> competition>";
1697                "(&&,<swan --> [bird]>,<swan --> (|,bird,swimmer)>)", "<swan --> [bird]>" => "<swan --> (|,bird,swimmer)>";
1698                "(&&,<swimmer --> animal>,<swimmer --> (|,swimmer,(-,animal,swan))>)", "<swimmer --> animal>" => "<swimmer --> (|,swimmer,(-,animal,swan))>";
1699                "(&&,<worms --> (/,food,{Tweety},_)>,<{Tweety} --> [chirping]>)", "[chirping]" => None;
1700                "(&&,<worms --> (/,food,{Tweety},_)>,<{Tweety} --> [chirping]>)", "{Tweety}" => None;
1701                "(&&,<{(*,a,b)} --> [like]>,<{(*,a,b)} --> (*,b,(/,like,_,b))>)", "<{(*,a,b)} --> [like]>" => "<{(*,a,b)} --> (*,b,(/,like,_,b))>";
1702                "(&&,<{(*,a,b)} --> like>,<{(*,b,a)} --> like>)", "<{(*,a,b)} --> like>" => "<{(*,b,a)} --> like>";
1703                "(&&,<{(|,boy,girl)} --> [youth]>,<{(|,boy,girl)} --> (|,girl,[strong])>)", "<{(|,boy,girl)} --> [youth]>" => "<{(|,boy,girl)} --> (|,girl,[strong])>";
1704                "(&&,<{Tweety} --> (&,[with_wings],(|,flyer,{Birdie}))>,<{{Tweety}} --> (&,[with_wings],(|,flyer,{Birdie}))>)", "<{{Tweety}} --> (&,[with_wings],(|,flyer,{Birdie}))>" => "<{Tweety} --> (&,[with_wings],(|,flyer,{Birdie}))>";
1705                "(&&,<{Tweety} --> (&,[with_wings],{Birdie})>,<{{Tweety}} --> (&,[with_wings],{Birdie})>)", "<{{Tweety}} --> (&,[with_wings],{Birdie})>" => "<{Tweety} --> (&,[with_wings],{Birdie})>";
1706                "(&&,<{Tweety} --> (&,flyer,[[with_wings]])>,<{{Tweety}} --> (&,flyer,[[with_wings]])>)", "<{{Tweety}} --> (&,flyer,[[with_wings]])>" => "<{Tweety} --> (&,flyer,[[with_wings]])>";
1707                "(&&,<{Tweety} --> (|,[[with_wings]],(&,flyer,{Birdie}))>,<{{Tweety}} --> (|,[[with_wings]],(&,flyer,{Birdie}))>)", "<{{Tweety}} --> (|,[[with_wings]],(&,flyer,{Birdie}))>" => "<{Tweety} --> (|,[[with_wings]],(&,flyer,{Birdie}))>";
1708                "(&&,<{Tweety} --> (|,bird,[yellow])>,<{{Tweety}} --> (|,bird,[yellow])>)", "<{Tweety} --> (|,bird,[yellow])>" => "<{{Tweety}} --> (|,bird,[yellow])>";
1709                "(&&,<{Tweety} --> (|,flyer,[[with_wings]])>,<{{Tweety}} --> (|,flyer,[[with_wings]])>)", "<{{Tweety}} --> (|,flyer,[[with_wings]])>" => "<{Tweety} --> (|,flyer,[[with_wings]])>";
1710                "(&&,<{Tweety} --> (|,flyer,[with_wings])>,<{{Tweety}} --> (|,flyer,[with_wings])>)", "<{{Tweety}} --> (|,flyer,[with_wings])>" => "<{Tweety} --> (|,flyer,[with_wings])>";
1711                "(&&,<{Tweety} --> (|,flyer,{Birdie})>,<{{Tweety}} --> (|,flyer,{Birdie})>)", "<{{Tweety}} --> (|,flyer,{Birdie})>" => "<{Tweety} --> (|,flyer,{Birdie})>";
1712                "(&&,<{Tweety} --> [chirping]>,<(*,{Tweety},worms) --> food>)", "[chirping]" => None;
1713                "(&&,<{Tweety} --> [chirping]>,<(*,{Tweety},worms) --> food>)", "{Tweety}" => None;
1714                "(&&,<{Tweety} --> [flyer]>,<{{Tweety}} --> [flyer]>)", "<{{Tweety}} --> [flyer]>" => "<{Tweety} --> [flyer]>";
1715                "(&&,<{Tweety} --> [yellow]>,<{{Tweety}} --> [yellow]>)", "<{Tweety} --> [yellow]>" => "<{{Tweety}} --> [yellow]>";
1716                "(&&,<{Tweety} --> [{Birdie}]>,<{Tweety} --> (&,flyer,[[with_wings]])>)", "<{Tweety} --> [{Birdie}]>" => "<{Tweety} --> (&,flyer,[[with_wings]])>";
1717                "(&&,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "<{Tweety} --> [with_wings]>" => "<{Tweety} --> bird>";
1718                "(&&,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "<{Tweety} --> bird>" => "<{Tweety} --> [with_wings]>";
1719                "(&&,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "[with_wings]" => None;
1720                "(&&,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "bird" => None;
1721                "(&&,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "{Tweety}" => None;
1722                "(&&,<{Tweety} --> flyer>,<(*,{Tweety},worms) --> food>)", "<(*,{Tweety},worms) --> food>" => "<{Tweety} --> flyer>";
1723                "(&&,<{Tweety} --> flyer>,<(*,{Tweety},worms) --> food>)", "<{Tweety} --> flyer>" => "<(*,{Tweety},worms) --> food>";
1724                "(&&,<{Tweety} --> flyer>,<(*,{Tweety},worms) --> food>)", "flyer" => None;
1725                "(&&,<{Tweety} --> flyer>,<(*,{Tweety},worms) --> food>)", "{Tweety}" => None;
1726                "(&&,<{Tweety} --> flyer>,<{Tweety} --> [{Birdie}]>)", "<{Tweety} --> [{Birdie}]>" => "<{Tweety} --> flyer>";
1727                "(&&,<{Tweety} --> flyer>,<{{Tweety}} --> flyer>)", "<{{Tweety}} --> flyer>" => "<{Tweety} --> flyer>";
1728                "(&&,<{[smart]} --> [bright]>,<{[smart]} --> [[bright]]>)", "<{[smart]} --> [[bright]]>" => "<{[smart]} --> [bright]>";
1729                "(&&,<{bird} --> animal>,<(&,robin,swimmer) --> animal>)", "<{bird} --> animal>" => "<(&,robin,swimmer) --> animal>";
1730                "(&&,<{key1} --> (/,open,_,{lock1})>,<{{key1}} --> (/,open,_,{lock1})>)", "<{key1} --> (/,open,_,{lock1})>" => "<{{key1}} --> (/,open,_,{lock1})>";
1731                "(&&,<{key1} --> [key]>,<{lock1} --> [(/,open,key1,_)]>)", "<{key1} --> [key]>" => "<{lock1} --> [(/,open,key1,_)]>";
1732                "(&&,<{key1} --> [key]>,<{lock1} --> [(/,open,{key1},_)]>)", "<{key1} --> [key]>" => "<{lock1} --> [(/,open,{key1},_)]>";
1733                "(&&,<{key1} --> key>,<{key1} --> (/,open,_,{lock1})>)", "<{key1} --> key>" => "<{key1} --> (/,open,_,{lock1})>";
1734                "(&&,<{lock1} --> [lock]>,<{lock1} --> [(/,open,{key1},_)]>)", "<{lock1} --> [(/,open,{key1},_)]>" => "<{lock1} --> [lock]>";
1735                "(&&,<{lock1} --> lock>,<{lock1} --> (/,open,key,_)>)", "<{lock1} --> (/,open,key,_)>" => "<{lock1} --> lock>";
1736                "(&&,<{robin} --> (&,bird,swimmer)>,<{robin} --> (-,bird,swimmer)>)", "<{robin} --> (-,bird,swimmer)>" => "<{robin} --> (&,bird,swimmer)>";
1737                "(&&,<{robin} --> [[chirping]]>,<{robin} --> [[flying]]>)", "<{robin} --> [[chirping]]>" => "<{robin} --> [[flying]]>";
1738                "(&&,<{robin} --> [[chirping]]>,<{robin} --> [[flying]]>,<{robin} --> [[with_wings]]>)", "<{robin} --> [[chirping]]>" => "(&&,<{robin} --> [[flying]]>,<{robin} --> [[with_wings]]>)";
1739                "(&&,<{robin} --> [[flying]]>,<{robin} --> [[with_wings]]>)", "<{robin} --> [bird]>" => None;
1740                "(&&,<{robin} --> [animal]>,<{robin} --> [[flying]]>)", "<{robin} --> [[flying]]>" => "<{robin} --> [animal]>";
1741                "(&&,<{robin} --> [animal]>,<{robin} --> [[flying]]>)", "<{robin} --> [animal]>" => "<{robin} --> [[flying]]>";
1742                "(&&,<{robin} --> [chirping]>,<{robin} --> [flying]>)", "[chirping]" => None;
1743                "(&&,<{robin} --> [chirping]>,<{robin} --> [flying]>,<{robin} --> [with_wings]>)", "[chirping]" => None;
1744                "(&&,<{robin} --> [flying]>,<{robin} --> [with_wings]>)", "<{robin} --> [flying]>" => "<{robin} --> [with_wings]>";
1745                "(&&,<{robin} --> bird>,<{robin} --> [flying]>)", "<{robin} --> [with_wings]>" => None;
1746                "(&&,<{swan} --> [bird]>,<{swan} --> (&,bird,swimmer)>)", "<{swan} --> (&,bird,swimmer)>" => "<{swan} --> [bird]>";
1747                "(&&,<{swan} --> [bird]>,<{swan} --> (|,bird,swimmer)>)", "<{swan} --> (|,bird,swimmer)>" => "<{swan} --> [bird]>";
1748                "(&&,<{tim} --> [(/,uncle,_,tom)]>,<(/,(*,tim,tom),_,tom) --> [(/,uncle,_,tom)]>)", "<{tim} --> [(/,uncle,_,tom)]>" => "<(/,(*,tim,tom),_,tom) --> [(/,uncle,_,tom)]>";
1749                "(&&,<{{key1}} --> key>,<{{key1}} --> [(/,open,_,{lock1})]>)", "<{{key1}} --> [(/,open,_,{lock1})]>" => "<{{key1}} --> key>";
1750                "(&&,robin,(--,<robin ==> [flying]>))", "(--,<robin ==> [flying]>)" => "robin";
1751                "(&&,robin,(--,<robin ==> [flying]>))", "<robin ==> [flying]>" => None;
1752                "(&&,robin,(--,<robin ==> [flying]>))", "robin" => "(--,<robin ==> [flying]>)";
1753                "(&&,robin,(--,<robin ==> bird>))", "(--,<robin ==> bird>)" => "robin";
1754                "(&&,robin,(--,<robin ==> bird>))", "<robin ==> bird>" => None;
1755                "(&&,robin,(--,<robin ==> bird>))", "robin" => "(--,<robin ==> bird>)";
1756                "(&&,robin,<robin ==> [chirping]>)", "<robin ==> [chirping]>" => "robin";
1757                "(&&,robin,<robin ==> [chirping]>)", "robin" => "<robin ==> [chirping]>";
1758                "(&&,robin,<robin ==> [chirping]>,<robin ==> [flying]>)", "(&&,robin,<robin ==> [chirping]>)" => "<robin ==> [flying]>";
1759                "(&&,robin,<robin ==> [chirping]>,<robin ==> [flying]>)", "[flying]" => None;
1760                "(&&,robin,<robin ==> [chirping]>,<robin ==> [flying]>)", "robin" => "(&&,<robin ==> [chirping]>,<robin ==> [flying]>)";
1761                "(&&,robin,<robin ==> [chirping]>,<robin ==> [flying]>,<robin ==> [with_wings]>)", "[flying]" => None;
1762                "(&&,robin,<robin ==> [chirping]>,<robin ==> [flying]>,<robin ==> [with_wings]>)", "robin" => "(&&,<robin ==> [chirping]>,<robin ==> [flying]>,<robin ==> [with_wings]>)";
1763                "(&&,robin,<robin ==> [chirping]>,<robin ==> [with_wings]>)", "<robin ==> [chirping]>" => "(&&,robin,<robin ==> [with_wings]>)";
1764                "(&&,robin,<robin ==> [flying]>)", "[flying]" => None;
1765                "(&&,robin,<robin ==> bird>)", "<robin ==> bird>" => "robin";
1766                "(&&,robin,<robin ==> bird>)", "bird" => None;
1767                "(&&,robin,<robin ==> bird>)", "robin" => "<robin ==> bird>";
1768                "(&&,robin,<robin ==> bird>,<robin ==> [flying]>)", "(&&,robin,(--,<robin ==> bird>))" => "(&&,<robin ==> bird>,<robin ==> [flying]>)";
1769                "(&&,robin,<robin ==> bird>,<robin ==> [flying]>)", "<robin ==> [flying]>" => "(&&,robin,<robin ==> bird>)";
1770                "(&&,robin,<robin ==> bird>,<robin ==> [flying]>)", "<robin ==> bird>" => "(&&,robin,<robin ==> [flying]>)";
1771                "(&&,robin,<robin ==> bird>,<robin ==> [flying]>)", "[flying]" => None;
1772                "(&&,robin,<robin ==> bird>,<robin ==> [flying]>)", "bird" => None;
1773                "(&&,robin,<robin ==> bird>,<robin ==> [flying]>)", "robin" => "(&&,<robin ==> bird>,<robin ==> [flying]>)";
1774                "(&,(*,0),(*,(*,0)))", "(*,0)" => "(*,(*,0))";
1775                "(&,(/,neutralization,_,base),(/,neutralization,_,soda),(/,reaction,_,(/,reaction,acid,_)))", "(/,reaction,_,(/,reaction,acid,_))" => "(&,(/,neutralization,_,base),(/,neutralization,_,soda))";
1776                "(&,(|,bird,robin),(|,robin,swimmer))", "(|,robin,swimmer)" => "(|,bird,robin)";
1777                "(&,CAT,(/,(/,REPRESENT,_,<(*,CAT,FISH) --> FOOD>),_,eat,fish))", "CAT" => "(/,(/,REPRESENT,_,<(*,CAT,FISH) --> FOOD>),_,eat,fish)";
1778                "(&,animal,swimmer)", "animal" => "swimmer";
1779                "(&,bird,[yellow])", "bird" => "[yellow]";
1780                "(&,bird,{Birdie})", "bird" => "{Birdie}";
1781                "(&,chess,(|,chess,sport))", "chess" => "(|,chess,sport)";
1782                "(&,flyer,[[with_wings]])", "flyer" => "[[with_wings]]";
1783                "(&,gull,robin,swan)", "robin" => "(&,gull,swan)";
1784                "(&,key,(/,open,_,{lock1}))", "key" => "(/,open,_,{lock1})";
1785                "(&,tim,(|,{tim},(/,(*,tim,tom),_,tom)))", "tim" => "(|,{tim},(/,(*,tim,tom),_,tom))";
1786                "(*,(/,num,_))", "(/,num,_)" => None;
1787                "(*,0)", "0" => None;
1788                "(*,a,b)", "(*,b,a)" => None;
1789                "(-,bird,(-,mammal,swimmer))", "bird" => "(-,mammal,swimmer)";
1790                "(-,bird,swimmer)", "bird" => "swimmer";
1791                "(-,{Mars,Pluto,Venus},[{Pluto,Saturn}])", "[{Pluto,Saturn}]" => "{Mars,Pluto,Venus}";
1792                "(|,(-,{Mars,Pluto,Venus},[{Pluto,Saturn}]),{Pluto,Saturn})", "(-,{Mars,Pluto,Venus},[{Pluto,Saturn}])" => "{Pluto,Saturn}";
1793                "(|,[{Pluto,Saturn}],{Mars,Pluto,Venus})", "[{Pluto,Saturn}]" => "{Mars,Pluto,Venus}";
1794                "(|,[{Pluto,Saturn}],{Mars,Venus})", "[{Pluto,Saturn}]" => "{Mars,Venus}";
1795                "(|,animal,swimmer,(-,animal,swan))", "swimmer" => "(|,animal,(-,animal,swan))";
1796                "(|,bird,(-,mammal,swimmer))", "bird" => "(-,mammal,swimmer)";
1797                "(|,bird,[yellow])", "bird" => "[yellow]";
1798                "(|,bird,robin)", "bird" => "robin";
1799                "(|,boy,girl,youth,[strong])", "youth" => "(|,boy,girl,[strong])";
1800                "(|,key,(/,open,_,lock))", "key" => "(/,open,_,lock)";
1801                "(|,key,(/,open,_,{lock1}))", "key" => "(/,open,_,{lock1})";
1802                "(|,like,{(*,a,b)})", "like" => "{(*,a,b)}";
1803                "(|,lock,[(/,open,key1,_)])", "lock" => "[(/,open,key1,_)]";
1804                "(|,tim,{tim},(/,(*,tim,tom),_,tom))", "tim" => "(|,{tim},(/,(*,tim,tom),_,tom))";
1805                "(||,(&&,<robin --> [bird]>,<robin --> [[flying]]>),<robin --> [[with_wings]]>)", "(&&,<robin --> [bird]>,<robin --> [[flying]]>)" => "<robin --> [[with_wings]]>";
1806                "(||,(&&,<robin --> [bird]>,<robin --> [[flying]]>),<robin --> [[with_wings]]>)", "<robin --> [[flying]]>" => None;
1807                "(||,(&&,<robin --> [bird]>,<robin --> [[flying]]>),<robin --> [[with_wings]]>)", "robin" => None;
1808                "(||,(&&,<{robin} --> [[flying]]>,<{robin} --> [[with_wings]]>),<{robin} --> [bird]>)", "(&&,<{robin} --> [[flying]]>,<{robin} --> [[with_wings]]>)" => "<{robin} --> [bird]>";
1809                "(||,(&&,<{robin} --> [[flying]]>,<{robin} --> [[with_wings]]>),<{robin} --> [bird]>)", "<{robin} --> [[with_wings]]>" => None;
1810                "(||,(&&,<{robin} --> [[flying]]>,<{robin} --> [[with_wings]]>),<{robin} --> [bird]>)", "<{robin} --> [bird]>" => "(&&,<{robin} --> [[flying]]>,<{robin} --> [[with_wings]]>)";
1811                "(||,(&&,<{robin} --> bird>,<{robin} --> [flying]>),<{robin} --> [with_wings]>)", "<{robin} --> [flying]>" => None;
1812                "(||,(&&,<{robin} --> bird>,<{robin} --> [flying]>),<{robin} --> [with_wings]>)", "[with_wings]" => None;
1813                "(||,<robin --> [[flying]]>,<robin --> [[with_wings]]>)", "<robin --> [[flying]]>" => "<robin --> [[with_wings]]>";
1814                "(||,<robin --> [[flying]]>,<robin --> [[with_wings]]>)", "robin" => None;
1815                "(||,<robin --> [animal]>,<robin --> [bird]>)", "<robin --> [animal]>" => "<robin --> [bird]>";
1816                "(||,<robin --> [animal]>,<robin --> [bird]>)", "robin" => None;
1817                "(||,<robin --> [bird]>,<robin --> [[flying]]>)", "<robin --> [[flying]]>" => "<robin --> [bird]>";
1818                "(||,<robin --> [bird]>,<robin --> [[flying]]>)", "<robin --> [bird]>" => "<robin --> [[flying]]>";
1819                "(||,<robin --> [bird]>,<robin --> [[flying]]>)", "robin" => None;
1820                "(||,<robin --> bird>,<robin --> [living]>)", "<robin --> [living]>" => "<robin --> bird>";
1821                "(||,<robin --> bird>,<robin --> [living]>)", "<robin --> bird>" => "<robin --> [living]>";
1822                "(||,<robin --> bird>,<robin --> [living]>)", "[living]" => None;
1823                "(||,<robin --> bird>,<robin --> [living]>)", "bird" => None;
1824                "(||,<robin --> bird>,<robin --> flyer>)", "<robin --> flyer>" => "<robin --> bird>";
1825                "(||,<robin --> bird>,<robin --> flyer>)", "bird" => None;
1826                "(||,<robin <-> swimmer>,<robin <-> [flying]>)", "<robin <-> [flying]>" => "<robin <-> swimmer>";
1827                "(||,<robin <-> swimmer>,<robin <-> [flying]>)", "<robin <-> swimmer>" => "<robin <-> [flying]>";
1828                "(||,<robin <-> swimmer>,<robin <-> [flying]>)", "[flying]" => None;
1829                "(||,<robin <-> swimmer>,<robin <-> [flying]>)", "robin" => None;
1830                "(||,<robin <=> swimmer>,<robin <=> [flying]>)", "<robin <=> [flying]>" => "<robin <=> swimmer>";
1831                "(||,<robin <=> swimmer>,<robin <=> [flying]>)", "<robin <=> swimmer>" => "<robin <=> [flying]>";
1832                "(||,<robin <=> swimmer>,<robin <=> [flying]>)", "[flying]" => None;
1833                "(||,<robin <=> swimmer>,<robin <=> [flying]>)", "robin" => None;
1834                "(||,<robin ==> swimmer>,<robin ==> [flying]>)", "<robin ==> [flying]>" => "<robin ==> swimmer>";
1835                "(||,<robin ==> swimmer>,<robin ==> [flying]>)", "<robin ==> swimmer>" => "<robin ==> [flying]>";
1836                "(||,<robin ==> swimmer>,<robin ==> [flying]>)", "[flying]" => None;
1837                "(||,<robin ==> swimmer>,<robin ==> [flying]>)", "robin" => None;
1838                "(||,<{Tweety} --> [with_wings]>,<{Tweety} --> [[with_wings]]>)", "<{Tweety} --> [[with_wings]]>" => "<{Tweety} --> [with_wings]>";
1839                "(||,<{Tweety} --> [with_wings]>,<{Tweety} --> [[with_wings]]>)", "<{Tweety} --> [with_wings]>" => "<{Tweety} --> [[with_wings]]>";
1840                "(||,<{Tweety} --> [with_wings]>,<{Tweety} --> [[with_wings]]>)", "[with_wings]" => None;
1841                "(||,<{Tweety} --> [with_wings]>,<{Tweety} --> [[with_wings]]>)", "{Tweety}" => None;
1842                "(||,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "<{Tweety} --> [with_wings]>" => "<{Tweety} --> bird>";
1843                "(||,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "<{Tweety} --> bird>" => "<{Tweety} --> [with_wings]>";
1844                "(||,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "[with_wings]" => None;
1845                "(||,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "bird" => None;
1846                "(||,<{Tweety} --> bird>,<{Tweety} --> [with_wings]>)", "{Tweety}" => None;
1847                "(||,<{lock1} --> [(/,open,{key1},_)]>,<{{lock1}} --> [(/,open,key1,_)]>)", "<{lock1} --> [(/,open,{key1},_)]>" => "<{{lock1}} --> [(/,open,key1,_)]>";
1848                "(||,<{lock1} --> [(/,open,{key1},_)]>,<{{lock1}} --> [(/,open,key1,_)]>)", "<{{lock1}} --> [(/,open,key1,_)]>" => "<{lock1} --> [(/,open,{key1},_)]>";
1849                "(~,boy,girl)", "boy" => "girl";
1850                "[(*,acid,base)]", "(*,acid,base)" => None;
1851                "[(/,reaction,_,base)]", "(/,reaction,_,base)" => None;
1852                "[acid]", "acid" => None;
1853                "[{Mars,Pluto,Venus}]", "{Mars,Pluto,Venus}" => None;
1854                "[{Pluto,Saturn}]", "{Pluto,Saturn}" => None;
1855                "{(*,a,b)}", "(*,a,b)" => None;
1856                "{(/,num,_)}", "(/,num,_)" => None;
1857                "{(|,boy,girl)}", "(|,boy,girl)" => None;
1858                "{(~,boy,girl)}", "(~,boy,girl)" => None;
1859                "{0}", "0" => None;
1860                "{Mars,Pluto,Saturn,Venus}", "{Mars,Pluto,Venus}" => None;
1861                "{Mars,Pluto,Saturn,Venus}", "{Pluto,Saturn}" => "{Mars,Venus}";
1862                "{Mars,Pluto,Venus}", "{Mars,Venus}" => None;
1863                "{[bright]}", "[bright]" => None;
1864            }
1865            ok!()
1866        }
1867
1868        #[test]
1869        fn set_component() -> AResult {
1870            /// ! 📝【2024-06-18 23:56:37】教训:不要在宏展开里头写过程式代码
1871            /// * * ℹ️宏展开里头的代码,每个都是实实在在要「一个个铺开」被编译器看到的
1872            /// * * ⚠️若直接在里头写过程式代码,即便代码只有十多行,但若有成百上千个测试用例,则代码行数会成倍增长
1873            /// * * 💥过多的代码行数,编译器就会爆炸
1874            fn test(compound: Term, index: usize, term: Option<Term>, expected: Option<Term>) {
1875                let compound_ref = compound.as_compound().expect("构造出来的不是复合词项");
1876                let compound_s = compound.to_string();
1877                let term_s = format_option_term(&term);
1878                let out = CompoundTermRef::set_component(compound_ref, index, term);
1879                assert_eq!(
1880                    out,
1881                    expected,
1882                    "{compound_s:?}, {index:?}, {term_s:?} => {} != {}",
1883                    format_option_term(&out),
1884                    format_option_term(&expected),
1885                );
1886            }
1887            macro_once! {
1888                // * 🚩模式:参数列表 ⇒ 预期词项
1889                macro test($($compound:tt, $index:tt, $term:tt => $expected:tt;)*) {
1890                    $( test(term!($compound), $index, option_term!($term), option_term!($expected)); )*
1891                }
1892                // * ℹ️用例均源自OpenNARS实例运行
1893                // ! ⚠️【2024-06-19 01:35:33】若在「可交换词项」中使用,则可能因为「呈现顺序与实际顺序不同」导致用例错误
1894                // * 📝OpenNARS基本只会在「合取」中使用——这导致版本间因「排序方式不同」而在测试用例上有偏差"(*, <robin --> [chirping]>, <robin --> [flying]>)", 0, "<robin --> bird>" => "(*, <robin --> bird>, <robin --> [flying]>)"
1895                "(*, <robin --> [chirping]>, <robin --> [flying]>, (||, <robin --> bird>, <robin --> flyer>))", 0, None => "(*, <robin --> [flying]>, (||, <robin --> bird>, <robin --> flyer>))";
1896                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [living]>)", 0, None => "(*, <robin --> [flying]>, <robin --> [living]>)";
1897                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [living]>)", 2, None => "(*, <robin --> [chirping]>, <robin --> [flying]>)";
1898                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [with_wings]>)", 0, "<robin --> bird>" => "(*, <robin --> bird>, <robin --> [flying]>, <robin --> [with_wings]>)";
1899                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [with_wings]>)", 0, None => "(*, <robin --> [flying]>, <robin --> [with_wings]>)";
1900                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [with_wings]>)", 1, None => "(*, <robin --> [chirping]>, <robin --> [with_wings]>)";
1901                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [with_wings]>)", 2, "(||, <robin --> bird>, <robin --> flyer>)" => "(*, <robin --> [chirping]>, <robin --> [flying]>, (||, <robin --> bird>, <robin --> flyer>))";
1902                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [with_wings]>)", 2, "<robin --> [living]>" => "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [living]>)";
1903                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [with_wings]>)", 2, "<robin --> bird>" => "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> bird>)";
1904                "(*, <robin --> [chirping]>, <robin --> [flying]>, <robin --> [with_wings]>)", 2, None => "(*, <robin --> [chirping]>, <robin --> [flying]>)";
1905                "(*, <robin --> [chirping]>, <robin --> [with_wings]>)", 0, "<robin --> bird>" => "(*, <robin --> bird>, <robin --> [with_wings]>)";
1906                "(*, <robin --> [chirping]>, <robin --> [with_wings]>)", 1, "(||, <robin --> bird>, <robin --> flyer>)" => "(*, <robin --> [chirping]>, (||, <robin --> bird>, <robin --> flyer>))";
1907                "(*, <robin --> [chirping]>, <robin --> [with_wings]>)", 1, "<robin --> [living]>" => "(*, <robin --> [chirping]>, <robin --> [living]>)";
1908                "(*, <robin --> [chirping]>, <robin --> [with_wings]>)", 1, "<robin --> bird>" => "(*, <robin --> [chirping]>, <robin --> bird>)";
1909                "(*, <robin --> [chirping]>, <robin --> [with_wings]>)", 1, "<robin --> flyer>" => "(*, <robin --> [chirping]>, <robin --> flyer>)";
1910                "(*, <robin --> [chirping]>, <robin --> [with_wings]>, <(*, robin, worms) --> food>)", 0, "<robin --> bird>" => "(*, <robin --> bird>, <robin --> [with_wings]>, <(*, robin, worms) --> food>)";
1911                "(*, <robin --> [chirping]>, <robin --> [with_wings]>, <(*, robin, worms) --> food>)", 0, None => "(*, <robin --> [with_wings]>, <(*, robin, worms) --> food>)";
1912                "(*, <robin --> [chirping]>, <robin --> [with_wings]>, <worms --> (/, food, robin, _)>)", 0, None => "(*, <robin --> [with_wings]>, <worms --> (/, food, robin, _)>)";
1913                "(*, <robin --> [flying]>, <robin --> [with_wings]>)", 1, "(||, <robin --> bird>, <robin --> flyer>)" => "(*, <robin --> [flying]>, (||, <robin --> bird>, <robin --> flyer>))";
1914                "(*, <robin --> [flying]>, <robin --> [with_wings]>)", 1, "<robin --> bird>" => "(*, <robin --> [flying]>, <robin --> bird>)";
1915                "(*, <robin --> flyer>, <(*, robin, worms) --> food>)", 0, "<robin --> bird>" => "(*, <robin --> bird>, <(*, robin, worms) --> food>)";
1916                "(*, <robin --> flyer>, <robin --> [chirping]>, <(*, robin, worms) --> food>)", 1, "<robin --> bird>" => "(*, <robin --> flyer>, <robin --> bird>, <(*, robin, worms) --> food>)";
1917                "(*, <robin --> flyer>, <robin --> [chirping]>, <(*, robin, worms) --> food>)", 1, None => "(*, <robin --> flyer>, <(*, robin, worms) --> food>)";
1918                "(*, <robin --> flyer>, <robin --> [chirping]>, <worms --> (/, food, robin, _)>)", 0, None => "(*, <robin --> [chirping]>, <worms --> (/, food, robin, _)>)";
1919                "(*, <robin --> flyer>, <robin --> [chirping]>, <worms --> (/, food, robin, _)>)", 1, "<robin --> bird>" => "(*, <robin --> flyer>, <robin --> bird>, <worms --> (/, food, robin, _)>)";
1920                "(*, <robin <-> [chirping]>, <robin <-> [flying]>)", 0, "<bird <-> robin>" => "(*, <bird <-> robin>, <robin <-> [flying]>)";
1921                "(*, <robin <-> [chirping]>, <robin <-> [flying]>, <robin <-> [with_wings]>)", 0, "<bird <-> robin>" => "(*, <bird <-> robin>, <robin <-> [flying]>, <robin <-> [with_wings]>)";
1922                "(*, <robin <-> [chirping]>, <robin <-> [flying]>, <robin <-> [with_wings]>)", 0, None => "(*, <robin <-> [flying]>, <robin <-> [with_wings]>)";
1923                "(*, <robin <-> [chirping]>, <robin <-> [flying]>, <robin <-> [with_wings]>)", 1, None => "(*, <robin <-> [chirping]>, <robin <-> [with_wings]>)";
1924                "(*, <robin <-> [chirping]>, <robin <-> [flying]>, <robin <-> [with_wings]>)", 2, None => "(*, <robin <-> [chirping]>, <robin <-> [flying]>)";
1925                "(*, <robin <-> [chirping]>, <robin <-> [with_wings]>)", 1, "<bird <-> robin>" => "(*, <robin <-> [chirping]>, <bird <-> robin>)";
1926                "(*, <robin <-> [flying]>, <robin <-> [with_wings]>)", 1, "<bird <-> robin>" => "(*, <robin <-> [flying]>, <bird <-> robin>)";
1927                "(*, <worms --> (/, food, {Tweety}, _)>, <{Tweety} --> flyer>, <{Tweety} --> [chirping]>)", 1, None => "(*, <worms --> (/, food, {Tweety}, _)>, <{Tweety} --> [chirping]>)";
1928                "(*, <{Tweety} --> flyer>, <{Tweety} --> [chirping]>, <(*, {Tweety}, worms) --> food>)", 0, None => "(*, <{Tweety} --> [chirping]>, <(*, {Tweety}, worms) --> food>)";
1929                "(*, <{Tweety} --> flyer>, <{Tweety} --> [chirping]>, <(*, {Tweety}, worms) --> food>)", 1, None => "(*, <{Tweety} --> flyer>, <(*, {Tweety}, worms) --> food>)";
1930                "(*, <{Tweety} --> flyer>, <{Tweety} --> [chirping]>, <(*, {Tweety}, worms) --> food>)", 2, None => "(*, <{Tweety} --> flyer>, <{Tweety} --> [chirping]>)";
1931                "(*, <{robin} --> [chirping]>, <{robin} --> [flying]>, <{robin} --> [with_wings]>)", 0, None => "(*, <{robin} --> [flying]>, <{robin} --> [with_wings]>)";
1932                "(*, <{robin} --> [chirping]>, <{robin} --> [flying]>, <{robin} --> [with_wings]>)", 1, None => "(*, <{robin} --> [chirping]>, <{robin} --> [with_wings]>)";
1933                "(*, <{robin} --> [chirping]>, <{robin} --> [flying]>, <{robin} --> [with_wings]>)", 2, None => "(*, <{robin} --> [chirping]>, <{robin} --> [flying]>)";
1934                "(*, <{robin} --> [flying]>, <{robin} --> [with_wings]>)", 1, "<{robin} --> bird>" => "(*, <{robin} --> [flying]>, <{robin} --> bird>)";
1935                "(*, robin, <robin ==> [chirping]>, <robin ==> [flying]>)", 0, None => "(*, <robin ==> [chirping]>, <robin ==> [flying]>)";
1936                "(*, robin, <robin ==> [chirping]>, <robin ==> [flying]>)", 1, None => "(*, robin, <robin ==> [flying]>)";
1937                "(*, robin, <robin ==> [chirping]>, <robin ==> [flying]>)", 2, None => "(*, robin, <robin ==> [chirping]>)";
1938                "(*, robin, <robin ==> [chirping]>, <robin ==> [flying]>, <robin ==> [with_wings]>)", 0, None => "(*, <robin ==> [chirping]>, <robin ==> [flying]>, <robin ==> [with_wings]>)";
1939                "(*, robin, <robin ==> [chirping]>, <robin ==> [flying]>, <robin ==> [with_wings]>)", 1, None => "(*, robin, <robin ==> [flying]>, <robin ==> [with_wings]>)";
1940                "(*, robin, <robin ==> [chirping]>, <robin ==> [flying]>, <robin ==> [with_wings]>)", 2, None => "(*, robin, <robin ==> [chirping]>, <robin ==> [with_wings]>)";
1941                "(*, robin, <robin ==> [chirping]>, <robin ==> [flying]>, <robin ==> [with_wings]>)", 3, None => "(*, robin, <robin ==> [chirping]>, <robin ==> [flying]>)";
1942                "(*, robin, <robin ==> [chirping]>, <robin ==> [with_wings]>)", 0, None => "(*, <robin ==> [chirping]>, <robin ==> [with_wings]>)";
1943                "(*, robin, <robin ==> [chirping]>, <robin ==> [with_wings]>)", 1, None => "(*, robin, <robin ==> [with_wings]>)";
1944                "(*, robin, <robin ==> [chirping]>, <robin ==> [with_wings]>)", 2, None => "(*, robin, <robin ==> [chirping]>)";
1945                "(*, robin, <robin ==> [flying]>, <robin ==> [with_wings]>)", 0, None => "(*, <robin ==> [flying]>, <robin ==> [with_wings]>)";
1946                "(*, robin, <robin ==> [flying]>, <robin ==> [with_wings]>)", 1, None => "(*, robin, <robin ==> [with_wings]>)";
1947                "(*, robin, <robin ==> [flying]>, <robin ==> [with_wings]>)", 2, None => "(*, robin, <robin ==> [flying]>)";
1948                "(*, robin, <robin ==> bird>, <robin ==> [flying]>)", 0, None => "(*, <robin ==> bird>, <robin ==> [flying]>)";
1949                "(*, robin, <robin ==> bird>, <robin ==> [flying]>)", 1, None => "(*, robin, <robin ==> [flying]>)";
1950                "(*, robin, <robin ==> bird>, <robin ==> [flying]>)", 2, None => "(*, robin, <robin ==> bird>)";
1951                "(*, robin, <robin ==> bird>, <robin ==> [living]>)", 0, None => "(*, <robin ==> bird>, <robin ==> [living]>)";
1952                "(*, robin, <robin ==> bird>, <robin ==> [living]>)", 1, None => "(*, robin, <robin ==> [living]>)";
1953                "(*, robin, <robin ==> bird>, <robin ==> [living]>)", 2, None => "(*, robin, <robin ==> bird>)";
1954                "(*, robin, <robin ==> swimmer>, <robin ==> [flying]>)", 0, None => "(*, <robin ==> swimmer>, <robin ==> [flying]>)";
1955                "(*, robin, <robin ==> swimmer>, <robin ==> [flying]>)", 1, None => "(*, robin, <robin ==> [flying]>)";
1956                "(*, robin, <robin ==> swimmer>, <robin ==> [flying]>)", 2, None => "(*, robin, <robin ==> swimmer>)";
1957            }
1958            ok!()
1959        }
1960    }
1961
1962    /// 复合词项可变引用
1963    mod compound_term_ref_mut {
1964        use super::*;
1965
1966        /// 保证整个接口是安全的
1967        #[test]
1968        #[allow(unused_variables)]
1969        pub fn assure_safe_interface() -> AResult {
1970            fn use_inner(_: &mut Term) {}
1971            fn use_components(_: &mut [Term]) {}
1972            let mut term = term!("(*, A, B, C)");
1973            let mut mut_compound = term.as_compound_mut().expect("无法转换为可变复合词项");
1974
1975            // 先用元素集合,再用词项自身
1976            let components = mut_compound.components();
1977            let inner = mut_compound.inner();
1978            // ! 在这之后是用不了`components`的:因为`inner`已经借走了`mut_compound`的引用
1979            // * 📝实际上`components`的生命周期早已在`inner`处结束,只是因为「自动作用域调整」才【显得】可以共存
1980            // use_terms(components);
1981            use_inner(inner);
1982            // * ✅下面这个是被允许的:有方式保证inner与整体不会同时出现,那就是让inner生命期在这之前结束
1983            use_components(mut_compound.components());
1984            // drop(inner); // ! 在这之后同样用不了`inner`:不允许整体被同时可变借用两次
1985            use_inner(mut_compound.inner()); // * ✅这个是被允许的:上头的可变引用创建后就被传入(然后回收)
1986
1987            // 先用词项自身,再用元素集合
1988            let inner = mut_compound.inner();
1989            let components = mut_compound.components();
1990            // ! 在这之后是用不了`inner`的:因为`components`已经借走了`mut_compound`的引用
1991            // * 📝实际上`inner`的生命周期早已在`components`处结束,只是因为「自动作用域调整」才【显得】可以共存
1992            // use_term(inner);
1993            use_components(components);
1994            // * ✅下面这个是被允许的:有方式保证inner与整体不会同时出现,那就是让components生命期在这之前结束
1995            use_inner(mut_compound.inner());
1996            // drop(components); // ! 在这之后同样用不了`inner`:不允许整体被同时可变借用两次
1997            use_components(mut_compound.components()); // * ✅这个是被允许的:上头的可变引用创建后就被传入(然后回收)
1998
1999            // components; // * 📌接下来不再允许使用`components`:中间可变借用了mut_compound,因此生命期被限定在借用之前
2000            // inner; // * 📌接下来不再允许使用`inner`:中间可变借用了mut_compound,因此生命期被限定在借用之前
2001
2002            ok!()
2003        }
2004
2005        /// 解引用:可变/不可变
2006        /// * ✅同时测试[`Deref`]与[`DerefMut`]
2007        #[test]
2008        fn deref_and_mut() -> AResult {
2009            /// 通用测试函数
2010            #[allow(clippy::explicit_auto_deref)]
2011            fn test(mut term: Term) {
2012                // * 🚩首先是一个复合词项
2013                assert!(term.is_compound());
2014                // * 🚩无检查转换到复合词项(可变引用)
2015                let term2 = term.clone();
2016                let mut compound = unsafe { term.as_compound_mut_unchecked() };
2017                // dbg!(term.as_compound_mut()); // * ✅安全:借用检查拦截了「重复借用」行为
2018
2019                // * 🚩像一个普通的词项(不可变引用)使用:一次只能传入一个
2020                // dbg!(compound.identifier(), compound.components());
2021                dbg!(compound.identifier());
2022                dbg!(compound.components());
2023
2024                // * 🚩像一个普通的词项(可变引用)使用:一次只能传入一个
2025                dbg!(compound.components_mut());
2026                let original_id = compound.identifier().to_string();
2027                let (id, _) = compound.id_comp_mut();
2028                *id = "MUTATED".into(); // * 🚩自动解引用并修改字段
2029                assert_eq!(*id, "MUTATED");
2030                *id = original_id; // * 🚩与上述语法等价,但这次是改回原标识符
2031
2032                // * 🚩检验潜在风险:使用Deref拷贝出并存的不可变引用
2033                let compound_ref = compound.as_compound().unwrap();
2034                // (compound_ref, compound);
2035                // * ✅安全:生命期约束下,不可变引用与可变引用无法同时存在
2036                // * 📝在调用`.as_compound()`之后,返回值的生命期即不可变引用的生命期
2037                // * 📝因此在「得到的不可变引用」生命期结束前,不能使用可变引用
2038                dbg!(compound_ref, compound_ref, compound_ref); // ! 转换成的不可变引用,可以同时存在多个
2039
2040                // * 🚩其它属性的验证
2041                asserts! {
2042                    compound.is_compound(),
2043                    compound.as_compound().is_some(),
2044                    compound.as_compound_mut().is_some(),
2045                    // ! 可变引用未实现Clone和Copy特征,但因实现了Deref而可以使用clone方法
2046                    *compound => term2, // ! 这毕竟是引用,需要解引用才能
2047                    compound.clone() => term2, // ! 引用的复制=自身的复制
2048                    (*compound).clone() => term2, // ! 解引用后复制,结果仍相等
2049                }
2050            }
2051            macro_once! {
2052                // * 🚩模式:词项字符串 ⇒ 预期
2053                macro test($( $term:literal )*) {$(
2054                    test(term!($term));
2055                )*}
2056                // // 占位符
2057                // "_" => 0
2058                // // 原子词项
2059                // "A" => 0
2060                // "$A" => 0
2061                // "#A" => 0
2062                // "?A" => 0
2063                // 复合词项
2064                "{A}"
2065                "[A]"
2066                "(&, A, B)" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
2067                "(|, A, B)"
2068                "(-, A, B)"
2069                "(~, A, B)"
2070                "(*, A, B, C)"
2071                "(/, R, _)"
2072                r"(\, R, _)"
2073                 "(&&, A, B)"
2074                 "(||, A, B)"
2075                 "(--, A)"
2076                // 陈述
2077                "<A --> B>"
2078                "<A <-> B>"
2079                "<A ==> B>"
2080                "<A <=> B>"
2081            }
2082            ok!()
2083        }
2084
2085        #[test]
2086        pub fn components() -> AResult {
2087            macro_once! {
2088                macro test($($term:literal => $container:expr)*) {
2089                    asserts! {$(
2090                            compound!(mut $term).components()
2091                            => $container
2092                    )*}
2093                }
2094                "{A}" => [term!(A)]
2095                "(--, A)" => [term!(A)]
2096                "(-, A, B)" => term!(["A", "B"])
2097                "(~, A, B)" => term!(["A", "B"])
2098                "{A, B, C}" => term!(["A", "B", "C"])
2099                "[A, B, C]" => term!(["A", "B", "C"])
2100                "(*, A, B, C)" => term!(["A", "B", "C"])
2101                "(/, A, B, C, _)" => term!(["A", "B", "C", "_"])
2102                "<A --> B>" => term!(["A", "B"])
2103                "<A <-> B>" => term!(["A", "B"])
2104                "<A ==> B>" => term!(["A", "B"])
2105                "<A <=> B>" => term!(["A", "B"])
2106                "<A --> B>" => term!(["A", "B"])
2107                "<A <-> B>" => term!(["A", "B"])
2108                "<A ==> B>" => term!(["A", "B"])
2109                "<A <=> B>" => term!(["A", "B"])
2110            }
2111            ok!()
2112        }
2113
2114        #[test]
2115        pub fn into_ref() -> AResult {
2116            macro_once! {
2117                macro test($($term:literal)*) {
2118                    asserts! {$(
2119                            compound!(mut $term).into_ref()
2120                            => compound!($term)
2121                    )*}
2122                }
2123                "{A}"
2124                "(--, A)"
2125                "(-, A, B)"
2126                "(~, A, B)"
2127                "{A, B, C}"
2128                "[A, B, C]"
2129                "(*, A, B, C)"
2130                "(/, A, B, C, _)"
2131                "<A --> B>"
2132                "<A <-> B>"
2133                "<A ==> B>"
2134                "<A <=> B>"
2135            }
2136            ok!()
2137        }
2138
2139        // ! ℹ️【2024-06-19 18:16:10】现在此处直接在特定引用处设置值
2140        #[test]
2141        pub fn set_term_when_dealing_variables() -> AResult {
2142            fn test(mut term: Term, i: usize, new: Term, expected: Term) {
2143                term.as_compound_mut().unwrap().components()[i] = new;
2144                assert_eq!(term, expected);
2145            }
2146            macro_once! {
2147                macro test($(
2148                    $term:literal [$i:expr] = $new:literal =>
2149                    $expected:literal
2150                )*) {
2151                    $( test( term!($term), $i, term!($new), term!($expected)); )*
2152                }
2153                "{A}"[0] = "B" => "{B}"
2154                "(--, A)"[0] = "B" => "(--, B)"
2155                "(-, A, B)"[0] = "a" => "(-, a, B)"
2156                "(~, A, B)"[0] = "a" => "(~, a, B)"
2157                "{A, B, Z}"[1] = "X" => "{A, X, Z}" // ! 集合词项在从字符串解析时会重排,所以不能用`C`
2158                "[A, B, Z]"[1] = "X" => "[A, X, Z]" // ! 集合词项在从字符串解析时会重排,所以不能用`C`
2159                "(*, A, B, C)"[1] = "X" => "(*, A, X, C)"
2160                "(/, A, _, B, C)"[2] = "X" => "(/, A, _, X, C)"
2161                "<A --> B>"[0] = "a" => "<a --> B>"
2162                "<A <-> B>"[1] = "X" => "<A <-> X>" // ! 可交换词项解析时重排
2163                "<A ==> B>"[0] = "a" => "<a ==> B>"
2164                "<A <=> B>"[1] = "X" => "<A <=> X>" // ! 可交换词项解析时重排
2165            }
2166            ok!()
2167        }
2168
2169        #[test]
2170        pub fn reorder_components() -> AResult {
2171            fn test(mut term: Term, i: usize, new: Term, expected: Term) {
2172                let mut ref_mut = term.as_compound_mut().unwrap();
2173                ref_mut.components()[i] = new;
2174                // * 🚩设置后排序
2175                ref_mut.reorder_components();
2176                assert_eq!(term, expected);
2177            }
2178            macro_once! {
2179                macro test($(
2180                    $term:literal [$i:expr] = $new:literal =>
2181                    $expected:literal
2182                )*) {
2183                    $( test( term!($term), $i, term!($new), term!($expected)); )*
2184                }
2185                "{A, B, C}"[1] = "X" => "{A, X, C}" // ! 集合词项在从字符串解析时会重排,但在重排后仍然相等
2186                "[A, B, C]"[1] = "X" => "[A, X, C]" // ! 集合词项在从字符串解析时会重排,但在重排后仍然相等
2187                "<A <-> B>"[0] = "a" => "<a <-> B>" // ! 可交换词项解析时重排,但在重排后仍然相等
2188                "<A <=> B>"[0] = "a" => "<a <=> B>" // ! 可交换词项解析时重排,但在重排后仍然相等
2189            }
2190            ok!()
2191        }
2192    }
2193
2194    /// 具所有权的复合词项
2195    mod compound_term {
2196        use super::*;
2197        use std::str::FromStr;
2198
2199        /// 词项之间的类型转换
2200        /// * 📄[`Term::try_into`] / [`CompoundTerm::try_from`]
2201        /// * 📄[`Term::from`] / [`CompoundTerm::into`]
2202        #[test]
2203        fn from_into() -> AResult {
2204            /// 通用测试函数
2205            fn test(compound: CompoundTerm) {
2206                // * 🚩首先是一个复合词项
2207                assert!(compound.is_compound());
2208
2209                // * 🚩从内部拷贝一个词项后,仍可无损转换为复合词项
2210                let term: Term = (*compound).clone();
2211                let _: CompoundTerm = term.try_into().expect("应该是复合词项!");
2212
2213                // * 🚩解包成普通词项后,仍可无损转换为复合词项
2214                let term: Term = compound.into();
2215                let _: CompoundTerm = term.try_into().expect("应该是复合词项!");
2216            }
2217            macro_once! {
2218                // * 🚩模式:词项字符串 ⇒ 预期
2219                macro test($( $term:literal )*) {$(
2220                    test(test_compound!(box $term));
2221                )*}
2222                // 普通复合词项
2223                "{A}"
2224                "[A]"
2225                "(&, A, B)" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
2226                "(|, A, B)"
2227                "(-, A, B)"
2228                "(~, A, B)"
2229                "(*, A, B, C)"
2230                "(/, R, _)"
2231                r"(\, R, _)"
2232                 "(&&, A, B)"
2233                 "(||, A, B)"
2234                 "(--, A)"
2235                // 陈述
2236                "<A --> B>"
2237                "<A <-> B>"
2238                "<A ==> B>"
2239                "<A <=> B>"
2240            }
2241            ok!()
2242        }
2243
2244        #[test]
2245        fn get_ref() -> AResult {
2246            /// 通用测试函数
2247            fn test(compound: CompoundTerm) {
2248                // * 🚩首先是一个复合词项
2249                assert!(compound.is_compound());
2250
2251                // * 🚩获取大小
2252                let size = compound.get_ref().size();
2253                println!("{compound}.size() => {size}");
2254
2255                // * 🚩遍历所有元素
2256                compound
2257                    .get_ref()
2258                    .components()
2259                    .iter()
2260                    .enumerate()
2261                    .for_each(|(i, component)| println!("    [{i}] => {component}"))
2262            }
2263            macro_once! {
2264                // * 🚩模式:词项字符串 ⇒ 预期
2265                macro test($( $term:literal )*) {$(
2266                    test(test_compound!(box $term));
2267                )*}
2268                // 普通复合词项
2269                "{A}"
2270                "[A]"
2271                "(&, A, B)" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
2272                "(|, A, B)"
2273                "(-, A, B)"
2274                "(~, A, B)"
2275                "(*, A, B, C)"
2276                "(/, R, _)"
2277                r"(\, R, _)"
2278                 "(&&, A, B)"
2279                 "(||, A, B)"
2280                 "(--, A)"
2281                // 陈述
2282                "<A --> B>"
2283                "<A <-> B>"
2284                "<A ==> B>"
2285                "<A <=> B>"
2286            }
2287            ok!()
2288        }
2289
2290        #[test]
2291        fn mut_ref() -> AResult {
2292            /// 通用测试函数
2293            fn test(mut compound: CompoundTerm) -> AResult {
2294                // * 🚩首先是一个复合词项
2295                assert!(compound.is_compound());
2296
2297                // * 🚩修改:更改第一个元素
2298                let old_s = compound.to_string();
2299                let mut mut_ref = compound.mut_ref();
2300                let first = &mut mut_ref.components()[0];
2301                let x = term!("X");
2302                *first = x.clone();
2303                println!("modification: {old_s:?} => \"{compound}\"");
2304                assert_eq!(compound.get_ref().components[0], x); // 假定修改后的结果
2305
2306                // * 🚩遍历修改所有元素
2307                compound
2308                    .mut_ref()
2309                    .components()
2310                    .iter_mut()
2311                    .enumerate()
2312                    .for_each(|(i, component)| {
2313                        *component = Term::from_str(&format!("T{i}")).unwrap()
2314                    });
2315                print!(" => \"{compound}\"");
2316
2317                ok!()
2318            }
2319            macro_once! {
2320                // * 🚩模式:词项字符串 ⇒ 预期
2321                macro test($( $term:literal )*) {$(
2322                    test(test_compound!(box $term))?;
2323                )*}
2324                // 普通复合词项
2325                "{A}"
2326                "[A]"
2327                "(&, A, B)" // ! 📌需要两个元素,防止被`make`约简;内涵交、合取、析取 同理
2328                "(|, A, B)"
2329                "(-, A, B)"
2330                "(~, A, B)"
2331                "(*, A, B, C)"
2332                "(/, R, _)"
2333                r"(\, R, _)"
2334                 "(&&, A, B)"
2335                 "(||, A, B)"
2336                 "(--, A)"
2337                // 陈述
2338                "<A --> B>"
2339                "<A <-> B>"
2340                "<A ==> B>"
2341                "<A <=> B>"
2342            }
2343            ok!()
2344        }
2345    }
2346}