narust_158/language/base/
construct.rs

1//! 实现 / 构造
2
3use super::structs::*;
4use crate::symbols::*;
5use anyhow::Result;
6use nar_dev_utils::*;
7
8impl Term {
9    /// 构造函数
10    /// * ⚠️有限性:仅限在「内部」使用,不希望外部以此构造出「不符范围」的词项
11    /// * 📌【2024-09-07 13:07:41】进一步限定可见性:只在**当前模块**中使用
12    fn new(identifier: impl Into<String>, components: TermComponents) -> Self {
13        Self {
14            identifier: identifier.into(),
15            components,
16        }
17    }
18
19    // 原子词项 //
20    // * ℹ️此处一系列构造方法对标OpenNARS中各「词项」的构造函数
21    // * ⚠️在MakeTerm中另有一套方法(参见term_making.rs)
22
23    /// NAL-1 / 词语
24    pub(super) fn new_word(name: impl Into<String>) -> Self {
25        Self::new(WORD, TermComponents::Word(name.into()))
26    }
27
28    /// NAL-4 / 占位符
29    /// * 📌【2024-04-21 00:36:27】需要一个「占位符」词项,以便和「词法Narsese」打交道
30    /// * 🚩仅使用「占位符标识符+空组分」表示
31    /// * 🎯仅在解析时临时出现
32    /// * ⚠️【2024-04-25 09:45:51】不允许外部直接创建
33    pub(super) fn new_placeholder() -> Self {
34        Self::new(PLACEHOLDER, TermComponents::Empty)
35    }
36
37    /// NAL-6 / 变量(内部统一代码)
38    /// * ℹ️外部统一使用[`Self::from_var_similar`]
39    fn new_var(identifier: impl Into<String>, id: impl Into<usize>) -> Self {
40        Self::new(identifier.into(), TermComponents::Variable(id.into()))
41    }
42
43    /// NAL-6 / 独立变量
44    pub(super) fn new_var_i(id: impl Into<usize>) -> Self {
45        Self::new_var(VAR_INDEPENDENT, id.into())
46    }
47
48    /// NAL-6 / 非独变量
49    pub(super) fn new_var_d(id: impl Into<usize>) -> Self {
50        Self::new_var(VAR_DEPENDENT, id.into())
51    }
52
53    /// NAL-6 / 查询变量
54    pub(super) fn new_var_q(id: impl Into<usize>) -> Self {
55        Self::new_var(VAR_QUERY, id.into())
56    }
57
58    /// 从「变量类型」与「id」构造一个变量
59    /// * 🎯在「变量替换」中创建新变量
60    ///   * 📌【2024-09-07 16:17:57】因为外部「变量处理」要用到,此处暂且放开
61    /// * ⚠️【2024-04-25 23:08:20】内部使用:会导致产生无效类型(改变了组分类型)
62    pub(in super::super) fn from_var_similar(
63        var_type: impl Into<String>,
64        new_id: impl Into<usize>,
65    ) -> Self {
66        Self::new_var(var_type, new_id)
67    }
68
69    // 复合词项 //
70
71    /// NAL-3 / 外延集
72    /// * 🚩【2024-04-21 13:39:28】使用统一的「无序不重复集合」构造组分
73    pub(super) fn new_set_ext(terms: impl Into<Vec<Term>>) -> Self {
74        Self::new(SET_EXT_OPERATOR, TermComponents::new_multi(terms.into()))
75    }
76
77    /// NAL-3 / 内涵集
78    /// * 🚩【2024-04-21 13:39:28】使用统一的「无序不重复集合」构造组分
79    pub(super) fn new_set_int(terms: impl Into<Vec<Term>>) -> Self {
80        Self::new(SET_INT_OPERATOR, TermComponents::new_multi(terms.into()))
81    }
82
83    /// NAL-3 / 外延交
84    /// * 🚩【2024-04-21 13:39:28】使用统一的「无序不重复集合」构造组分
85    pub(super) fn new_intersection_ext(terms: impl Into<Vec<Term>>) -> Self {
86        Self::new(
87            INTERSECTION_EXT_OPERATOR,
88            TermComponents::new_multi(terms.into()),
89        )
90    }
91
92    /// NAL-3 / 内涵交
93    /// * 🚩【2024-04-21 13:39:28】使用统一的「无序不重复集合」构造组分
94    pub(super) fn new_intersection_int(terms: impl Into<Vec<Term>>) -> Self {
95        Self::new(
96            INTERSECTION_INT_OPERATOR,
97            TermComponents::new_multi(terms.into()),
98        )
99    }
100
101    /// NAL-3 / 外延差
102    pub(super) fn new_diff_ext(term1: Term, term2: Term) -> Self {
103        Self::new(
104            DIFFERENCE_EXT_OPERATOR,
105            TermComponents::new_binary(term1, term2),
106        )
107    }
108
109    /// NAL-3 / 内涵差
110    pub(super) fn new_diff_int(term1: Term, term2: Term) -> Self {
111        Self::new(
112            DIFFERENCE_INT_OPERATOR,
113            TermComponents::new_binary(term1, term2),
114        )
115    }
116
117    /// NAL-4 / 乘积
118    pub(super) fn new_product(terms: impl Into<Vec<Term>>) -> Self {
119        Self::new(PRODUCT_OPERATOR, TermComponents::new_multi(terms.into()))
120    }
121
122    /// NAL-4 / 外延像
123    /// * 📝占位符索引≠关系词项索引(in OpenNARS)
124    ///   * ⚠️占位符索引=0 ⇒ 不被允许
125    ///
126    /// ! ⚠️【2024-06-16 16:50:23】现在传入的「词项列表」将附带「像占位符」词项
127    pub(super) fn new_image_ext(terms: impl Into<Vec<Term>>) -> Result<Self> {
128        Ok(Self::new(
129            IMAGE_EXT_OPERATOR,
130            Self::_process_image_terms(terms)?,
131        ))
132    }
133
134    /// NAL-4 / 内涵像
135    /// * 📝占位符索引≠关系词项索引(in OpenNARS)
136    ///   * ⚠️占位符索引=0 ⇒ 不被允许
137    ///
138    /// ! ⚠️【2024-06-16 16:50:23】现在传入的「词项列表」将附带「像占位符」词项
139    pub(super) fn new_image_int(terms: impl Into<Vec<Term>>) -> Result<Self> {
140        Ok(Self::new(
141            IMAGE_INT_OPERATOR,
142            Self::_process_image_terms(terms)?,
143        ))
144    }
145
146    /// 代码复用之工具函数:处理像占位符和词项列表
147    /// * 🚩将词项列表转换为`Vec<Term>`
148    /// * 🚩检查占位符索引范围
149    /// * 🚩返回构造好的「词项组分」
150    /// * ⚠️会返回错误
151    ///
152    /// ! ⚠️【2024-06-16 16:50:23】现在传入的「词项列表」将附带「像占位符」词项
153    #[inline(always)]
154    fn _process_image_terms(terms: impl Into<Vec<Term>>) -> Result<TermComponents> {
155        // 转换词项列表
156        let terms = terms.into();
157        // 检索像占位符位置
158        let i_placeholder = terms.iter().position(Term::is_placeholder);
159        // 检查占位符索引范围
160        match i_placeholder {
161            Some(i_placeholder) => {
162                // * ✅`terms.iter().position`保证:占位符索引不会超出范围
163                if i_placeholder == 0 {
164                    return Err(anyhow::anyhow!("占位符不能压在「关系词项」的位置上"));
165                }
166            }
167            None => return Err(anyhow::anyhow!("未在像的元素中找到占位符")),
168        }
169        // 构造 & 返回
170        // * 🚩【2024-06-12 22:48:33】现在不再附带额外字段,统一使用一个枚举变种
171        Ok(TermComponents::new_multi(terms))
172    }
173
174    /// NAL-5 / 合取
175    /// * 🚩【2024-04-21 13:39:28】使用统一的「无序不重复集合」构造组分
176    pub(super) fn new_conjunction(terms: impl Into<Vec<Term>>) -> Self {
177        Self::new(
178            CONJUNCTION_OPERATOR,
179            TermComponents::new_multi(terms.into()),
180        )
181    }
182
183    /// NAL-5 / 析取
184    /// * 🚩【2024-04-21 13:39:28】使用统一的「无序不重复集合」构造组分
185    pub(super) fn new_disjunction(terms: impl Into<Vec<Term>>) -> Self {
186        Self::new(
187            DISJUNCTION_OPERATOR,
188            TermComponents::new_multi(terms.into()),
189        )
190    }
191
192    /// NAL-5 / 否定
193    pub(super) fn new_negation(term: Term) -> Self {
194        Self::new(NEGATION_OPERATOR, TermComponents::new_unary(term))
195    }
196
197    // 陈述 //
198
199    /// NAL-1 / 继承
200    pub(super) fn new_inheritance(subject: Term, predicate: Term) -> Self {
201        Self::new(
202            INHERITANCE_RELATION,
203            TermComponents::new_binary(subject, predicate),
204        )
205    }
206
207    /// NAL-3 / 相似
208    pub(super) fn new_similarity(subject: Term, predicate: Term) -> Self {
209        Self::new(
210            SIMILARITY_RELATION,
211            TermComponents::new_binary_unordered(subject, predicate),
212        )
213    }
214
215    /// NAL-5 / 蕴含
216    pub(super) fn new_implication(subject: Term, predicate: Term) -> Self {
217        Self::new(
218            IMPLICATION_RELATION,
219            TermComponents::new_binary(subject, predicate),
220        )
221    }
222
223    /// NAL-5 / 等价
224    pub(super) fn new_equivalence(subject: Term, predicate: Term) -> Self {
225        Self::new(
226            EQUIVALENCE_RELATION,
227            TermComponents::new_binary_unordered(subject, predicate),
228        )
229    }
230}
231
232impl TermComponents {
233    /// 一元组分
234    /// * 🚩【2024-06-12 22:43:34】现在封装「内部枚举变种」接口
235    pub(super) fn new_unary(term: Term) -> Self {
236        Self::Compound(Box::new([term]))
237    }
238
239    /// 二元有序组分
240    /// * 🚩【2024-06-12 22:43:34】现在封装「内部枚举变种」接口
241    pub(super) fn new_binary(term1: Term, term2: Term) -> Self {
242        Self::Compound(Box::new([term1, term2]))
243    }
244
245    /// 二元无序组分
246    /// * 🎯用于【双元素对称性】复合词项
247    /// * ⚠️无法去重:元素数量固定为`2`
248    /// * 📄相似、等价
249    /// * 🚩使用「临时数组切片」实现(较为简洁)
250    pub(super) fn new_binary_unordered(term1: Term, term2: Term) -> Self {
251        pipe! {
252            // 排序
253            manipulate!(
254                [term1, term2]
255                => .sort()
256            )
257            // 构造
258            => Box::new
259            => Self::Compound
260        }
261    }
262
263    /// 多元组分
264    /// * 📌兼容「有序可重复」「无序不重复」两种
265    /// * 🚩【2024-09-07 17:27:00】现在将「无序不重复组分」外包到[`super::making`]模块中
266    ///   * 📌在外部保证「有序性/无序性/可重复性/不重复性」
267    pub(super) fn new_multi(terms: Vec<Term>) -> Self {
268        pipe! {
269            terms
270            // 转换
271            => .into_boxed_slice()
272            // 构造
273            => Self::Compound
274        }
275    }
276}
277
278/// [「词项」](Term)的快捷构造宏
279#[macro_export]
280macro_rules! term {
281    // 单个词项(字符串)
282    ($s:literal) => {
283        $s.parse::<$crate::language::Term>()
284    };
285    // 单个词项,但unwrap
286    (unwrap $s:expr) => {
287        $s.parse::<$crate::language::Term>().unwrap()
288    };
289    // 单个词项,无需引号
290    ($($t:tt)*) => {
291        stringify!($($t)*).parse::<$crate::language::Term>()
292    };
293}
294
295/// 单元测试
296#[cfg(test)]
297mod tests {
298    use super::*;
299    use crate::{ok, test_term as t, util::AResult};
300    use nar_dev_utils::fail_tests;
301    // ! ❌使用`test_term as t`避免`term`重名:即便不导入,也会ambiguous
302
303    /// 测试/词项
304    #[test]
305    fn test_term() -> AResult {
306        // 测试一个词项
307        fn detect(term: &Term) {
308            use TermComponents::*;
309            match term.id_comp() {
310                (WORD, Word(name)) => {
311                    println!("word with {name:?}");
312                }
313                (IMAGE_EXT_OPERATOR, Compound(v)) => {
314                    let i = v.iter().position(Term::is_placeholder).unwrap();
315                    println!("ext_image '/' with {i}");
316                    println!("<components>");
317                    for term in v.iter() {
318                        detect(term);
319                    }
320                    println!("</components>");
321                }
322                _ => println!("term {:?}: {}", term.identifier, term.format_name()),
323            }
324        }
325        // 直接从内部构造函数中构造一个词项
326        let im_ext = Term::new(
327            IMAGE_EXT_OPERATOR,
328            TermComponents::new_multi(vec![Term::new_word("word"), Term::new_placeholder()]),
329        );
330        detect(&im_ext);
331        // 从「词法Narsese」中解析词项
332        detect(&t!("<A --> B>"));
333        detect(&t!("(--, [C, B, A, 0, 1, 2])"));
334        detect(&t!(
335            "{<B <-> A>, <D <=> C>, (&&, <A --> B>, <B --> C>), $i, #d, ?q}"
336        ));
337        detect(&t!("(/, _, A, B)"));
338        detect(&t!("(/, A, _, B)"));
339        detect(&t!("(/, A, B, _)"));
340        detect(&t!(r"(\, _, A, B)"));
341        detect(&t!(r"(\, A, _, B)"));
342        detect(&t!(r"(\, A, B, _)"));
343        // 返回成功
344        ok!()
345    }
346
347    // 失败测试
348    fail_tests! {
349        组分数不对_二元_外延差1 t!(unwrap "(-, A)");
350        组分数不对_二元_外延差3 t!(unwrap "(-, A, B, C)");
351        组分数不对_一元_否定 t!(unwrap "(--, A, B)");
352        空集_外延集 t!(unwrap "{}");
353        空集_内涵集 t!(unwrap "[]");
354        空集_外延像 t!(unwrap r"(/, _)");
355        空集_内涵像 t!(unwrap r"(\, _)");
356    }
357}