diff --git a/src/Narsese/Sentences/stamp.jl b/src/Narsese/Sentences/stamp.jl index 875bdd4..5345566 100644 --- a/src/Narsese/Sentences/stamp.jl +++ b/src/Narsese/Sentences/stamp.jl @@ -9,7 +9,8 @@ # 导出 export STAMP_TIME_TYPE, TIME_ETERNAL export AbstractStamp, Stamp -export StampBasic +export StampBasic, StampPythonic +export get_evidential_base, get_creation_time, get_put_in_time, get_occurrence_time """ @@ -60,6 +61,26 @@ const STAMP_TIME_TYPE::DataType = UInt # 根据PyNARS的语法要求,改为「 """ TIME_ETERNAL::STAMP_TIME_TYPE = typemin(STAMP_TIME_TYPE) +# 方法集 # + +"各个抽象Getter" +get_evidential_base(s::Stamp) = error("$(typeof(s)): 未实现的`get_evidential_base`方法!") +get_creation_time(s::Stamp) = error("$(typeof(s)): 未实现的`get_creation_time`方法!") +get_put_in_time(s::Stamp) = error("$(typeof(s)): 未实现的`get_put_in_time`方法!") +get_occurrence_time(s::Stamp) = error("$(typeof(s)): 未实现的`get_occurrence_time`方法!") + +"重定向运算符" +@inline Base.:(==)(s1::Stamp, s2::Stamp) = Base.isequal(s1, s2) +"判等の法:各个属性相等" +@inline Base.isequal(s1::Stamp, s2::Stamp) = ( + get_tense(s1) == get_tense(s2) && # 时态相等 + get_evidential_base(s1) == get_evidential_base(s2) && + get_creation_time(s1) == get_creation_time(s2) && + get_put_in_time(s1) == get_put_in_time(s2) && + get_occurrence_time(s1) == get_occurrence_time(s2) +) + +# 具体实现 """ 源:OpenNARS @@ -121,6 +142,11 @@ struct StampBasic{tense <: AbstractTense} <: AbstractStamp end end +get_evidential_base(s::StampBasic) = s.evidential_base +get_creation_time(s::StampBasic) = s.creation_time +get_put_in_time(s::StampBasic) = s.put_in_time +get_occurrence_time(s::StampBasic) = s.occurrence_time + "类型参数の默认值:无时态⇒「永恒」时态" StampBasic(args...) = StampBasic{Eternal}(args...) @@ -211,6 +237,12 @@ struct StampPythonic <: AbstractStamp end end +get_evidential_base(s::StampPythonic) = s.evidential_base +get_creation_time(s::StampPythonic) = s.creation_time +get_put_in_time(s::StampPythonic) = s.put_in_time +get_occurrence_time(s::StampPythonic) = s.occurrence_time + + begin "方法集" # 【20230815 16:33:51】函数「get_tense」已在「methods.jl」中定义 @@ -221,7 +253,9 @@ begin "方法集" """ 获取时态 """ - @inline get_tense(s::StampBasic{S}) where {S} = S + @inline (get_tense(::StampBasic{T})::TTense) where {T} = T + "Python化的「绝对时态」总是「永恒」" + @inline get_tense(s::StampPythonic)::TTense = TenseEternal "Python化的「相对时态」:与「发生时间」对比" @inline get_tense(s::StampPythonic, reference_time::STAMP_TIME_TYPE)::TTense = ( reference_time == s.occurrence_time ? @@ -231,6 +265,8 @@ begin "方法集" TenseFuture ) ) + "类型自动转换" + @inline get_tense(s::StampPythonic, reference_time::Integer)::TTense = get_tense(s, STAMP_TIME_TYPE(reference_time)) """ (用于「基础时间戳」)是否是由「固定时刻」 @@ -243,26 +279,5 @@ begin "方法集" ) "【20230815 23:45:19】Python版的暂且恒为true,因为并无「固定的时态」一说" @inline is_fixed_occurrence_time(s::StampPythonic) = true - - """ - 判等の法:相等@各个属性 - """ - @inline Base.:(==)(s1::StampBasic, s2::StampBasic)::Bool = ( - typeof(s1) == typeof(s2) && # 时态相等 - s1.evidential_base == s2.evidential_base && - s1.creation_time == s2.creation_time && - s1.put_in_time == s2.put_in_time && - s1.occurrence_time == s2.occurrence_time - ) - - """ - 判等の法:相等@各个属性 - """ - @inline Base.:(==)(s1::StampPythonic, s2::StampPythonic)::Bool = ( - s1.evidential_base == s2.evidential_base && - s1.creation_time == s2.creation_time && - s1.put_in_time == s2.put_in_time && - s1.occurrence_time == s2.occurrence_time - ) -end \ No newline at end of file +end diff --git a/src/Narsese/Sentences/truth.jl b/src/Narsese/Sentences/truth.jl index dc98c93..d5f146a 100644 --- a/src/Narsese/Sentences/truth.jl +++ b/src/Narsese/Sentences/truth.jl @@ -30,9 +30,9 @@ const Truth = ATruth = AbstractTruth # 抽象类方法 # "获取频率f" -get_f(t::Truth) = error("$t: 未实现的`get_f`方法!") +get_f(t::Truth) = error("$(typeof(t)): 未实现的`get_f`方法!") "获取信度c" -get_c(t::Truth) = error("$t: 未实现的`get_c`方法!") +get_c(t::Truth) = error("$(typeof(t)): 未实现的`get_c`方法!") """ 判等の法:相等@f,c diff --git a/src/Narsese/Tasks/budget.jl b/src/Narsese/Tasks/budget.jl index cb08b05..e5c0f87 100644 --- a/src/Narsese/Tasks/budget.jl +++ b/src/Narsese/Tasks/budget.jl @@ -33,11 +33,11 @@ const Budget = ABudget = AbstractBudget # 抽象类方法 # "获取优先级p" -get_p(b::Budget) = error("$b: 未实现的`get_p`方法!") +get_p(b::Budget) = error("$(typeof(b)): 未实现的`get_p`方法!") "获取耐久度d" -get_d(b::Budget) = error("$b: 未实现的`get_d`方法!") +get_d(b::Budget) = error("$(typeof(b)): 未实现的`get_d`方法!") "获取质量q" -get_q(b::Budget) = error("$b: 未实现的`get_q`方法!") +get_q(b::Budget) = error("$(typeof(b)): 未实现的`get_q`方法!") """ 判等の法:相等@p,d,q diff --git a/src/Narsese/Terms/methods.jl b/src/Narsese/Terms/methods.jl index fd0c823..b6c3b02 100644 --- a/src/Narsese/Terms/methods.jl +++ b/src/Narsese/Terms/methods.jl @@ -60,7 +60,7 @@ begin "NAL信息支持" - 等价于:虚方法/抽象方法 - 需要被子类实现 """ - @inline get_syntactic_complexity(::Term) = error("未定义的计算!") + @inline get_syntactic_complexity(t::Term) = error("$(typeof(t))未定义的计算!") """ (默认)原子の复杂度 = 1 diff --git a/src/Narsese/use_strict.jl b/src/Narsese/use_strict.jl index 7f3f2d3..248fefe 100644 --- a/src/Narsese/use_strict.jl +++ b/src/Narsese/use_strict.jl @@ -52,7 +52,9 @@ end # 临时定义陈述合法性:改变「内联合法性检查」逻辑 "继承&相似⇒是否为「一等公民」" @inline function check_valid(t::Statement{<:TermBasedSTs}) - ϕ1(t) ≠ ϕ2(t) && ϕ1(t) isa FOTerm && ϕ2(t) isa FOTerm + ϕ1(t) ≠ ϕ2(t) && + ϕ1(t) isa FOTerm && + ϕ2(t) isa FOTerm end "继承&相似⇒是否为「一等公民」" @@ -65,7 +67,9 @@ end "蕴含&等价⇒是否为「陈述词项」" @inline function check_valid(t::Statement{<:StatementBasedSTs}) - ϕ1(t) ≠ ϕ2(t) && ϕ1(t) isa AbstractStatement && ϕ2(t) isa AbstractStatement + ϕ1(t) ≠ ϕ2(t) && + ϕ1(t) isa StatementLike && + ϕ2(t) isa StatementLike end "蕴含&等价⇒是否为「陈述词项」" @@ -79,7 +83,8 @@ end "陈述逻辑集、陈述时序集:词项数>1 && 不支持「非陈述词项」" @inline function check_valid(t::ACompound{<:StatementBasedCTs}) - length(t) > 1 && all(term isa StatementLike for term in t) + length(t) > 1 && + all(term isa StatementLike for term in t) end "陈述逻辑集、陈述时序集:词项数>1 && 不支持「非陈述词项」" @inline function check_valid_explainable(t::ACompound{<:StatementBasedCTs}) diff --git a/src/Util/Util.jl b/src/Util/Util.jl index eb11f7c..d031965 100644 --- a/src/Util/Util.jl +++ b/src/Util/Util.jl @@ -4,7 +4,7 @@ module Util export UNothing -export @reverse_dict_content, @redirect_SRS, @expectedError +export @reverse_dict_content, @redirect_SRS, @hasError, @expectedError export match_first, match_first_view export allproperties, allproperties_generator, allproperties_named, allproperties_named_generator export empty_content @@ -35,6 +35,21 @@ macro redirect_SRS(para::Expr, code::Expr) return redirect_SRS(para, code) end +"【用于调试】判断「是否出错」(仿官方库show语法)" +macro hasError(exs...) + Expr(:block, [ # 生成一个block,并使用列表推导式自动填充args + quote + try + $(esc(ex)) + false + catch e + true + end + end + for ex in exs + ]...) # 别忘展开 +end + "【用于调试】判断「期望出错」(仿官方库show语法)" macro expectedError(exs...) Expr(:block, [ # 生成一个block,并使用列表推导式自动填充args diff --git a/test/test_construction.jl b/test/test_construction.jl index e34689a..199685d 100644 --- a/test/test_construction.jl +++ b/test/test_construction.jl @@ -7,13 +7,20 @@ @show w i d q o + p = PlaceHolder() @test w == Word(:词项)::Word @test i == IVar(:独立变量)::Variable{VTIndependent} @test d == DVar(:非独变量)::Variable{VTDependent} @test q == QVar(:查询变量)::Variable{VTQuery} + @test p == PlaceHolder()::PlaceHolder @test o == Operator(:操作)::Operator @test n == Interval(+137)::Interval + # 像占位符 + @test p == placeholder + @test nameof(p) == Symbol() + @test nameof_string(p) == "" + # 词项集 exSet = ⩀(w, d, o) inSet = ⊍(n, q, i) diff --git a/test/test_methods_arrays.jl b/test/test_methods_arrays.jl index ce81927..1f21a00 100644 --- a/test/test_methods_arrays.jl +++ b/test/test_methods_arrays.jl @@ -11,7 +11,7 @@ @test length(A) == 1 # 测试原子的索引函数 - @test getindex(A) == A[] == :A + @test getindex(A) == A[] == A[typemax(Int)] == A[typemin(Int)] == :A # 测试除差、像以外的所有复合词项 for compoundType::Type in [TermProduct, ExtSet, IntSet, ExtIntersection, IntIntersection] diff --git a/test/test_methods_nal.jl b/test/test_methods_nal.jl index 757ee75..7bbf16f 100644 --- a/test/test_methods_nal.jl +++ b/test/test_methods_nal.jl @@ -15,12 +15,19 @@ (A→B) in terms_ && (B→C) in terms_ && ((A→B)⇒(B→C)) in terms_ + # 获取所有索引 + t = ExtSet(A,B,C) + @test eachindex(t) == Base.OneTo(3) + @test nextind(t, 1) == 2 + @test prevind(t, 2) == 1 + # 是否可交换 # @test !is_commutative(StatementTypeInheritance) @test !is_commutative(StatementTypeImplication) @test is_commutative(StatementTypeSimilarity) @test is_commutative(StatementTypeEquivalence) - + + @test !is_commutative(Term) # 默认不可交换 @test !is_commutative(TermProduct) @test !is_commutative(ExtImage) @test !is_commutative(IntDiff) @@ -42,6 +49,7 @@ # 是否可重复:默认是`!(是否可交换)`,但**不用于判断陈述** # + @test is_repeatable(Term) # 默认可重复 @test is_repeatable(TermProduct) @test is_repeatable(ExtImage) @test is_repeatable(SeqConjunction) @@ -127,4 +135,35 @@ @test EquivalenceRetrospective(A→B, B→A) == EquivalencePredictive(B→A, A→B) + # 语句&任务 # + + # 时间戳 # + + sb = StampBasic() + sp1 = StampPythonic() + + @test sb == sp1 # 默认值应该相等 + @test sb !== sp1 # 不全等 + + sp2 = StampPythonic(occurrence_time = 1) + # 相对时序 + @test get_tense(sp2) == Eternal # 默认永恒 + @test get_tense(sp2, 0) == Future # sp2 是 0 的未来 + @test get_tense(sp2, 1) == Present # sp2 是 1 的现在 + @test get_tense(sp2, 2) == Past # sp2 是 2 的过去 + + @test sp2 == deepcopy(sp2) + @test sp1 != sp2 + + # 方法重定向 + for t in test_set.tasks, method_name in [:get_term, :get_stamp, :get_tense, :get_punctuation, :get_truth, :get_syntactic_complexity] + @test @eval $method_name($t) == $method_name(get_sentence($t)) + end + for t in test_set.tasks, method_name in [:get_p, :get_d, :get_q] + @test @eval $method_name($t) == $method_name(get_budget($t)) + end + for t in test_set.sentences, method_name in [:get_syntactic_complexity] + @test @eval $method_name($t) == $method_name(get_term($t)) + end + end diff --git a/test/test_methods_validity.jl b/test/test_methods_validity.jl index 1ced43c..27f37ae 100644 --- a/test/test_methods_validity.jl +++ b/test/test_methods_validity.jl @@ -54,4 +54,14 @@ @test @expectedError ParConjunction(A→B, C→D, A↔D, D→o, B→C, w) @test @expectedError SeqConjunction(A→B, D→o, B→C, A↔D, C→D, w) + # 所有词项的「可解释🆚非解释」「内部🆚外部」严格性应该相互等价 + for term::Term in test_set.terms + @test ( + check_valid(term) == + !(@hasError check_valid_explainable(term)) == + check_valid_external(term) == + !(@hasError check_valid_external_explainable(term)) + ) + end + end diff --git a/test/test_narsese.jl b/test/test_narsese.jl index 099842e..4ecc2f3 100644 --- a/test/test_narsese.jl +++ b/test/test_narsese.jl @@ -19,6 +19,9 @@ # 类型 # include("test_types.jl") + + # API # + include("test_narsese_api.jl") # 词项与数组等可迭代对象的联动方法 # include("test_methods.jl") diff --git a/test/test_narsese_api.jl b/test/test_narsese_api.jl new file mode 100644 index 0000000..9af5dda --- /dev/null +++ b/test/test_narsese_api.jl @@ -0,0 +1,35 @@ +(@isdefined JuNarsese) || include("commons.jl") # 已在此中导入JuNarsese、Test + +# 词项接口:用于后续扩展自定义词项/语句/任务 # +@testset "Narsese/API" begin + + # 定义几个没实现方法的抽象类型,以便测试在「调用未实现方法的报错」 # + struct TestTerm <: Term end + struct TestTruth <: Truth end + struct TestBudget <: Budget end + struct TestStamp <: Stamp end + + t = TestTerm() + tt = TestTruth() + ts = TestStamp() + tb = TestBudget() + + @test @expectedError get_syntactic_complexity(t) + + @test @expectedError get_f(tt) + @test @expectedError get_c(tt) + + @test @expectedError get_p(tb) + @test @expectedError get_d(tb) + @test @expectedError get_q(tb) + + @test @expectedError get_evidential_base(ts) + @test @expectedError get_creation_time(ts) + @test @expectedError get_put_in_time(ts) + @test @expectedError get_occurrence_time(ts) + + # 测试一些「抽象词项的默认值」 # + @test !is_commutative(t) # 默认不可交换 + @test is_repeatable(t) # 默认可重复 + +end