// ===== moonrdfs 全链自证 demo(验收役 2026-11-03;cmd/demo 家法形)=====
// MemoryDataset 门面七面:insert 集合律(重复装载折叠)/match_triples 全开/
// exec_bgp 变量连接/match_quads named-graph 分账/词典去重计/prefix 册往返/
// infer 物化闭包(四族六条;二跑 0)。
// 数据纪律:跨包 record 字面量一律拔带型 let(家法 #11/#22);插值内复杂
// 表达式一律上提 let(家法:插值内嵌引号咬串);insert/exec 的 raise 收敛
// 到 run 的 RdfStoreError 域,main 侧 catch 收 Bool。
///|
fn run() -> Bool raise {
let ds = @store.MemoryDataset::new()
ds.set_prefix("foaf", "http://xmlns.com/foaf/0.1/")
// 装店:alice 与 bob 互知,各带名字(字面量无 lang 无型)
let alice : @core.Term = @core.Term::Iri("http://example.org/alice")
let bob : @core.Term = @core.Term::Iri("http://example.org/bob")
let name_p : @core.Term = @core.Term::Iri("http://xmlns.com/foaf/0.1/name")
let knows_p : @core.Term = @core.Term::Iri("http://xmlns.com/foaf/0.1/knows")
let alice_name : @core.Term = @core.Term::Literal("Alice", None, None)
let bob_name : @core.Term = @core.Term::Literal("Bob", None, None)
let t1 : @core.Triple = { s: alice, p: name_p, o: alice_name, }
let t2 : @core.Triple = { s: bob, p: name_p, o: bob_name, }
let t3 : @core.Triple = { s: alice, p: knows_p, o: bob, }
let t4 : @core.Triple = { s: bob, p: knows_p, o: alice, }
println("--- 装店(insert 集合律)")
let r1 = ds.insert(t1)
let r2 = ds.insert(t2)
let r3 = ds.insert(t3)
let r4 = ds.insert(t4)
let r5 = ds.insert(t1) // 重复装载 → 折叠(false)
println("[解] 首装 4 条 = \{r1}\{r2}\{r3}\{r4};重复第 5 条 = \{r5}")
let ok_insert = r1 && r2 && r3 && r4 && !r5
println("--- match_triples 全开(s/p/o 缺省 = 无界)")
let all = ds.match_triples()
println("[解] 全开 \{all.length()} 条(重复折叠后)")
let ok_match = all.length() == 4
println(
"--- exec_bgp 三模式连接(?a foaf:name ?n)(?a foaf:knows ?b)(?b foaf:name ?m)",
)
let pa : @core.TriplePattern = {
s: @core.Var("a"),
p: @core.Fixed(name_p),
o: @core.Var("n"),
}
let pb : @core.TriplePattern = {
s: @core.Var("a"),
p: @core.Fixed(knows_p),
o: @core.Var("b"),
}
let pc : @core.TriplePattern = {
s: @core.Var("b"),
p: @core.Fixed(name_p),
o: @core.Var("m"),
}
let bgp : @core.Bgp = { patterns: [pa, pb, pc], }
let solutions = ds.exec_bgp(bgp)
println("[解] \{solutions.length()} 解")
for sol in solutions {
let ca : @core.Term = sol.get("a").unwrap()
let cn : @core.Term = sol.get("n").unwrap()
let cb : @core.Term = sol.get("b").unwrap()
let cm : @core.Term = sol.get("m").unwrap()
println(
" ?a=\{@core.canonical_of_term(ca)} ?n=\{@core.canonical_of_term(cn)} ?b=\{@core.canonical_of_term(cb)} ?m=\{@core.canonical_of_term(cm)}",
)
}
let ok_bgp = solutions.length() == 2 && bgp_names_ok(solutions)
println("--- 四元组面(named-graph 分账)")
let gb : @core.GraphName? = Some(@core.Named(bob))
let q : @core.Quad = { s: alice, p: knows_p, o: bob, g: @core.Named(bob), }
let _ = ds.insert_quad(q)
let quads = ds.match_quads(g=gb)
println("[解] named graph 账 \{quads.length()} 条")
let ok_quads = quads.length() == 1
println("--- 词典与 prefix 册")
let distinct = ds.distinct_term_count()
// prefix_of(key) = 按 prefix 名查回 namespace(set_prefix 的键值往返)
let prefix = ds.prefix_of("foaf")
let prefix_text = prefix.unwrap_or("(无)")
println("[解] 词典去重 \{distinct} 词;prefix 往返 = \{prefix_text}")
let ok_dict = distinct == 6 && prefix is Some("http://xmlns.com/foaf/0.1/")
println("--- infer 物化闭包(RDFS-lite 四族六条首现;二跑 0)")
let bird_c : @core.Term = @core.Term::Iri("http://example.org/Bird")
let animal_c : @core.Term = @core.Term::Iri("http://example.org/Animal")
let wings_p : @core.Term = @core.Term::Iri("http://example.org/wings")
let keet_x : @core.Term = @core.Term::Iri("http://example.org/keet")
let sub_c : @core.Term = @core.Term::Iri(@infer.RDFS_SUBCLASS_OF)
let dom_c : @core.Term = @core.Term::Iri(@infer.RDFS_DOMAIN)
let type_c : @core.Term = @core.Term::Iri(@infer.RDF_TYPE)
let blue_v : @core.Term = @core.Term::Literal("blue", None, None)
let _ = ds.insert({ s: bird_c, p: sub_c, o: animal_c, })
let _ = ds.insert({ s: wings_p, p: dom_c, o: bird_c, })
let _ = ds.insert({ s: keet_x, p: wings_p, o: blue_v, })
let n1 = ds.materialize()
let n2 = ds.materialize()
println(
"[解] 首物化 +\{n1}(域律 keet type Bird → 子类链 keet type Animal);二跑 +\{n2}",
)
let derived = ds.match_triples(
s=Some(keet_x),
p=Some(type_c),
o=Some(animal_c),
)
let ok_infer = n1 == 2 && n2 == 0 && derived.length() == 1
report("insert 集合律(重复折叠)", ok_insert)
report("全开匹配 4 条", ok_match)
report("BGP 互知双向恰两解(n/m 各含 Alice+Bob)", ok_bgp)
report("named-graph 恰一账", ok_quads)
report("词典 6 词 + prefix 往返", ok_dict)
report("infer 物化闭包(+2 / 二跑 0 / 派生可见)", ok_infer)
ok_insert && ok_match && ok_bgp && ok_quads && ok_dict && ok_infer
}
///|
/// BGP 双向解账(解序不钉——显式集合判,不走 sort:String 内建全序 =
/// (长度,内容),Bob 会排在 Alice 前,坑账第一条)
fn bgp_names_ok(solutions : Array[Map[String, @core.Term]]) -> Bool {
let ns : Array[String] = []
let ms : Array[String] = []
for sol in solutions {
let n = name_of(sol, "n")
let m = name_of(sol, "m")
if n == "" || m == "" || n == m {
return false
}
ns.push(n)
ms.push(m)
}
solutions.length() == 2 &&
string_in(ns, "Alice") &&
string_in(ns, "Bob") &&
string_in(ms, "Alice") &&
string_in(ms, "Bob")
}
///|
fn string_in(arr : Array[String], want : String) -> Bool {
for x in arr {
if x == want {
return true
}
}
false
}
///|
/// 解集取字面量词面(变量缺绑/非字面 = 空串——判定位)
fn name_of(sol : Map[String, @core.Term], key : String) -> String {
match sol.get(key) {
Some(term) =>
match term {
@core.Literal(v, _, _) => v
_ => ""
}
None => ""
}
}
///|
fn report(label : String, ok : Bool) -> Unit {
println("[判] \{label} ⇒ \{if ok { "✓" } else { "✗" }}")
}
///|
fn main {
let ok = run() catch {
_ => {
println("[判] 存储异常(不该发生)")
false
}
}
if !ok {
println("DEMO:FAIL")
abort("demo 期望失配——看上方 [判] ✗ 行")
}
println("DEMO:PASS")
}