narust_158/language/features/
image.rs

1//! 📄OpenNARS `nars.language.ImageXXt`
2//! * 🎯复刻OpenNARS中有关「外延像/内涵像」的通用函数
3//! * 📌NAL底层的「像」逻辑,对应`ImageExt`与`ImageInt`
4//! * ⚠️不包括与记忆区有关的`make`系列方法
5//!
6//! # 🆕差异点
7//! ! ⚠️因原先语法上实现的差异,此处对「像占位符位置」与「关系词项位置」的表述,和OpenNARS不一样
8//! * 📝NAL-4中,「像」作为一种「关系与参数中挖了空的词项」,
9//!   * 将**第一位**固定为「关系词项」的位置
10//! * 📌范围:1~总词项数
11//!   * ⚠️第一位为「关系词项」预留——若有占位符,则与「乘积」无异
12//! * 📌核心差异:自Narsese.rs以来,NARust更强调「占位符的词法位置」而非「关系词项之后的位置」
13//!
14//! ## 例
15//!
16//! 对`(*,A,B) --> P`
17//! * 在第1位
18//!   * 📄OpenNARS: ⇔ `A --> (/,P,_,B)` ⇒ `(/,P,B)_0`
19//!   * 📄NARust:   ⇔ `A --> (/,P,_,B)` ⇒ `(/,P,B)_1`
20//!     * 📌`1`而非`0`的依据:占位符在「像」中的位置为`1`
21//! * 在第2位
22//!   * 📄OpenNARS: ⇔ `B --> (/,P,A,_)` ⇒ `(/,A,P)_1`
23//!   * 📄NARust:   ⇔ `B --> (/,P,A,_)` ⇒ `(/,P,A)_2`
24//!     * 📌`2`而非`1`的依据:占位符在「像」中的位置为`2`
25//! * 在第0位(扩展)
26//!   * 📄OpenNARS: 【不支持】(会自动转换到「第一位」去)
27//!   * 📄NARust:   ⇔ `P --> (/,_,A,B)` ⇒ `(/,A,B)_0`
28//!     * 📌`0`的依据:占位符在「像」中的位置为`0`
29//!     * ❓PyNARS却又支持`(/,_,A)`,但又把`<P --> (/,_,A,B)>.`推导成`<(*, A, B)-->_>.`
30//!
31//! # 方法列表
32//! 🕒最后更新:【2024-04-24 20:15:43】
33//!
34//! * `ImageExt` / `ImageInt`
35//!   * `getRelationIndex`
36//!   * `getRelation`
37//!   * `getTheOtherComponent`
38//!
39//! # 📄OpenNARS
40//!
41//! ## 外延像
42//! An extension image.
43//!
44//! `B --> (/,P,A,_)` iff `(*,A,B) --> P`
45//!
46//! Internally, it is actually `(/,A,P)_1`, with an index.
47//!
48//! ## 内涵像
49//! An intension image.
50//!
51//! `(\,P,A,_) --> B` iff `P --> (*,A,B)`
52//!
53//! Internally, it is actually `(\,A,P)_1`, with an index.
54
55use crate::language::*;
56use nar_dev_utils::matches_or;
57
58impl<'a> CompoundTermRef<'a> {
59    // * ✅现在「判别函数」统一迁移至[`super::compound`]
60
61    /// 📄OpenNARS `getRelationIndex` 属性
62    /// * 🎯用于获取「像」的关系索引
63    /// * 🆕⚠️现在是获取「占位符位置」
64    ///   * 📝原先OpenNARS是将「关系词项」放在占位符处的,现在是根据《NAL》原意,将「关系词项」统一放在「第一个词项」处
65    ///   * 📌所以后续所有的「索引」都变成了「占位符位置」
66    ///   * 💭【2024-05-11 14:40:15】后续可能会在这点上有隐患——随后要注意这种差别
67    ///
68    /// # Panics
69    ///
70    /// ! ⚠️仅限于「像」的`TermComponents::MultiIndexed`词项
71    /// * 若尝试获取「非『像』词项」的关系索引,则会panic
72    /// * 🚩【2024-06-12 22:53:09】本来就不应该对「非像词项」调用该函数——严格跟「像」类型绑定
73    ///
74    /// # 📄OpenNARS
75    ///
76    /// get the index of the relation in the component list
77    ///
78    /// @return the index of relation
79    #[doc(alias = "get_relation_index")]
80    pub fn get_placeholder_index(self) -> usize {
81        self.components
82            .iter()
83            .position(Term::is_placeholder)
84            .expect("尝试获取「非『像』词项」的关系索引")
85    }
86
87    /// 📄OpenNARS `getRelation` 属性
88    /// * 🎯用于获取「像」的「关系词项」
89    /// * ⚠️若尝试获取「非『像』词项」的关系词项,则会panic
90    /// * 🆕按NARust「索引=占位符索引」的来:总是在索引`0`处
91    ///
92    /// # 📄OpenNARS
93    ///
94    /// Get the relation term in the Image
95    ///
96    /// @return The term representing a relation
97    pub fn get_relation(self) -> &'a Term {
98        &self.components[0]
99    }
100
101    /// 📄OpenNARS `getTheOtherComponent` 属性
102    /// * 🎯用于获取「像」的「另一词项」
103    /// * ⚠️若尝试获取「非『像』词项」的词项,则会panic
104    ///
105    /// # 📄OpenNARS
106    ///
107    /// Get the other term in the Image
108    ///
109    /// @return The term related
110    pub fn get_the_other_component(self) -> Option<&'a Term> {
111        /* 📄OpenNARS源码:
112        if (components.size() != 2) {
113            return null;
114        }
115        return (relationIndex == 0) ? components.get(1) : components.get(0); */
116        matches_or! {
117            ?self.components,
118            // ! 🚩【2024-06-13 23:52:06】现在「占位符」算作一个词项了
119            // * 📄[R, _, A]
120            [_, term1, term2] => match term1.is_placeholder() {
121                true => term2,
122                false => term1,
123            }
124        }
125    }
126}
127
128/// 单元测试
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use crate::symbols::*;
133    use crate::test_compound as compound;
134    use crate::test_term as term;
135    use crate::{ok, util::AResult};
136    use nar_dev_utils::asserts;
137
138    #[test]
139    fn instanceof_image() -> AResult {
140        /// 📌工具方法:直接调用`make_image_xxt_vec`构造词项
141        fn make_image(
142            argument: impl IntoIterator<Item = &'static str>,
143            make_vec: impl Fn(Vec<Term>) -> Option<Term>,
144        ) -> AResult<Term> {
145            let argument = argument
146                .into_iter()
147                .map(|t| t.parse::<Term>().expect("内部词项解析失败"))
148                .collect::<Vec<_>>();
149            make_vec(argument).ok_or(anyhow::anyhow!("词项解析失败"))
150        }
151        fn make_ext(argument: impl IntoIterator<Item = &'static str>) -> AResult<Term> {
152            make_image(argument, Term::make_image_ext_vec)
153        }
154        fn make_int(argument: impl IntoIterator<Item = &'static str>) -> AResult<Term> {
155            make_image(argument, Term::make_image_int_vec)
156        }
157        asserts! {
158            // 像占位符在第一位的「像」会被解析为「乘积」
159            term!(r"(/, _, A, B)").identifier() => PRODUCT_OPERATOR,
160            term!(r"(\, _, A, B)").identifier() => PRODUCT_OPERATOR,
161            // 其余正常情况
162            make_ext(["S", "_", "A", "B"])?.instanceof_image()
163            make_int(["S", "_", "A", "B"])?.instanceof_image()
164            make_ext(["S", "A", "_", "B"])?.instanceof_image()
165            make_int(["S", "A", "_", "B"])?.instanceof_image()
166            make_ext(["S", "A", "B", "_"])?.instanceof_image()
167            make_int(["S", "A", "B", "_"])?.instanceof_image()
168            term!(r"(/, A, _, B)").instanceof_image()
169            term!(r"(\, A, _, B)").instanceof_image()
170            term!(r"(/, A, B, _)").instanceof_image()
171            term!(r"(\, A, B, _)").instanceof_image()
172        }
173        ok!()
174    }
175
176    #[test]
177    fn get_relation_index() -> AResult {
178        asserts! {
179            // compound!(r"(/, _, A, B)").get_relation_index() => 0 // 会被解析为「乘积」
180            // compound!(r"(\, _, A, B)").get_relation_index() => 0 // 会被解析为「乘积」
181            compound!(r"(/, A, _, B)").get_placeholder_index() => 1
182            compound!(r"(\, A, _, B)").get_placeholder_index() => 1
183            compound!(r"(/, A, B, _)").get_placeholder_index() => 2
184            compound!(r"(\, A, B, _)").get_placeholder_index() => 2
185        }
186        ok!()
187    }
188
189    #[test]
190    fn get_relation() -> AResult {
191        asserts! {
192            compound!(r"(/, R, _, B)").get_relation() => &term!("R")
193            compound!(r"(\, R, _, B)").get_relation() => &term!("R")
194            compound!(r"(/, R, A, _)").get_relation() => &term!("R")
195            compound!(r"(\, R, A, _)").get_relation() => &term!("R")
196        }
197        ok!()
198    }
199
200    #[test]
201    fn get_the_other_component() -> AResult {
202        asserts! {
203            compound!(r"(/, R, _, B)").get_the_other_component() => Some(&term!("B"))
204            compound!(r"(\, R, _, B)").get_the_other_component() => Some(&term!("B"))
205            compound!(r"(/, R, A, _)").get_the_other_component() => Some(&term!("A"))
206            compound!(r"(\, R, A, _)").get_the_other_component() => Some(&term!("A"))
207        }
208        ok!()
209    }
210}