1use std::{cmp::Ordering, fmt};
24
25use iri_rs::{Iri, IriBuf};
26
27use crate::{BlankId, BlankIdBuf, Id, IsGraph, IsObject, IsPredicate, IsSubject, Literal, LiteralRef, LocalTerm, Quad, RdfDisplay, Term, Triple, __seal};
28
29#[derive(Debug, thiserror::Error)]
32pub enum GeneralizationError {
33 #[error("literal in subject position")]
34 LiteralSubject,
36 #[error("literal in predicate position")]
37 LiteralPredicate,
39 #[error("blank node in predicate position")]
40 BlankPredicate,
42 #[error("literal in graph position")]
43 LiteralGraph,
45 #[error("triple term in subject position")]
48 TripleTermSubject,
49 #[error("triple term in predicate position")]
51 TripleTermPredicate,
52 #[error("triple term in graph position")]
54 TripleTermGraph,
55}
56
57#[derive(Clone, Copy, Eq, Ord, Hash, Debug)]
59#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
60pub struct GeneralizedTriple<S = LocalTerm, P = S, O = S>(pub S, pub P, pub O);
61
62impl<S, P, O> GeneralizedTriple<S, P, O> {
63 pub const fn new(subject: S, predicate: P, object: O) -> Self {
65 Self(subject, predicate, object)
66 }
67
68 pub const fn subject(&self) -> &S {
70 &self.0
71 }
72
73 pub const fn predicate(&self) -> &P {
75 &self.1
76 }
77
78 pub const fn object(&self) -> &O {
80 &self.2
81 }
82
83 pub fn into_subject(self) -> S {
85 self.0
86 }
87
88 pub fn into_predicate(self) -> P {
90 self.1
91 }
92
93 pub fn into_object(self) -> O {
95 self.2
96 }
97
98 pub fn into_parts(self) -> (S, P, O) {
100 (self.0, self.1, self.2)
101 }
102
103 pub fn into_quad<G>(self, graph: Option<G>) -> GeneralizedQuad<S, P, O, G> {
105 GeneralizedQuad(self.0, self.1, self.2, graph)
106 }
107
108 pub fn map_subject<U>(self, f: impl FnOnce(S) -> U) -> GeneralizedTriple<U, P, O> {
110 GeneralizedTriple(f(self.0), self.1, self.2)
111 }
112
113 pub fn map_predicate<U>(self, f: impl FnOnce(P) -> U) -> GeneralizedTriple<S, U, O> {
115 GeneralizedTriple(self.0, f(self.1), self.2)
116 }
117
118 pub fn map_object<U>(self, f: impl FnOnce(O) -> U) -> GeneralizedTriple<S, P, U> {
120 GeneralizedTriple(self.0, self.1, f(self.2))
121 }
122
123 pub const fn as_ref(&self) -> GeneralizedTriple<&S, &P, &O> {
125 GeneralizedTriple(&self.0, &self.1, &self.2)
126 }
127}
128
129impl<S, P, O> GeneralizedTriple<&S, &P, &O> {
130 pub fn cloned(&self) -> GeneralizedTriple<S, P, O>
132 where
133 S: Clone,
134 P: Clone,
135 O: Clone,
136 {
137 GeneralizedTriple(self.0.clone(), self.1.clone(), self.2.clone())
138 }
139
140 pub fn into_cloned(self) -> GeneralizedTriple<S, P, O>
142 where
143 S: Clone,
144 P: Clone,
145 O: Clone,
146 {
147 GeneralizedTriple(self.0.clone(), self.1.clone(), self.2.clone())
148 }
149
150 pub const fn copied(&self) -> GeneralizedTriple<S, P, O>
152 where
153 S: Copy,
154 P: Copy,
155 O: Copy,
156 {
157 GeneralizedTriple(*self.0, *self.1, *self.2)
158 }
159
160 pub const fn into_copied(self) -> GeneralizedTriple<S, P, O>
162 where
163 S: Copy,
164 P: Copy,
165 O: Copy,
166 {
167 GeneralizedTriple(*self.0, *self.1, *self.2)
168 }
169}
170
171impl<T> GeneralizedTriple<T, T, T> {
172 pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> GeneralizedTriple<U, U, U> {
174 GeneralizedTriple(f(self.0), f(self.1), f(self.2))
175 }
176}
177
178impl GeneralizedTriple<LocalTerm, LocalTerm, LocalTerm> {
179 pub fn try_into_triple(self) -> Result<Triple<Id, IriBuf, LocalTerm>, GeneralizationError> {
184 let GeneralizedTriple(s, p, o) = self;
185 let s = local_term_to_id(s)?;
186 let p = local_term_to_iri(p)?;
187 Ok(Triple(s, p, o))
188 }
189}
190
191impl<S: IsSubject, P: IsPredicate, O: IsObject> From<Triple<S, P, O>> for GeneralizedTriple<S, P, O> {
192 fn from(t: Triple<S, P, O>) -> Self {
193 GeneralizedTriple(t.0, t.1, t.2)
194 }
195}
196
197impl<S1, P1, O1, S2, P2, O2> PartialEq<GeneralizedTriple<S2, P2, O2>> for GeneralizedTriple<S1, P1, O1>
198where
199 S1: PartialEq<S2>,
200 P1: PartialEq<P2>,
201 O1: PartialEq<O2>,
202{
203 fn eq(&self, other: &GeneralizedTriple<S2, P2, O2>) -> bool {
204 self.0 == other.0 && self.1 == other.1 && self.2 == other.2
205 }
206}
207
208impl<S1, P1, O1, S2, P2, O2> PartialOrd<GeneralizedTriple<S2, P2, O2>> for GeneralizedTriple<S1, P1, O1>
209where
210 S1: PartialOrd<S2>,
211 P1: PartialOrd<P2>,
212 O1: PartialOrd<O2>,
213{
214 fn partial_cmp(&self, other: &GeneralizedTriple<S2, P2, O2>) -> Option<Ordering> {
215 match self.0.partial_cmp(&other.0) {
216 Some(Ordering::Equal) => match self.1.partial_cmp(&other.1) {
217 Some(Ordering::Equal) => self.2.partial_cmp(&other.2),
218 cmp => cmp,
219 },
220 cmp => cmp,
221 }
222 }
223}
224
225impl<S: RdfDisplay, P: RdfDisplay, O: RdfDisplay> fmt::Display for GeneralizedTriple<S, P, O> {
226 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227 write!(f, "{} {} {}", self.0.rdf_display(), self.1.rdf_display(), self.2.rdf_display())
228 }
229}
230
231impl<S: RdfDisplay, P: RdfDisplay, O: RdfDisplay> RdfDisplay for GeneralizedTriple<S, P, O> {
232 fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
233 write!(f, "{} {} {}", self.0.rdf_display(), self.1.rdf_display(), self.2.rdf_display())
234 }
235}
236
237#[derive(Clone, Copy, Eq, Ord, Hash, Debug)]
239#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
240pub struct GeneralizedQuad<S = LocalTerm, P = S, O = S, G = S>(pub S, pub P, pub O, pub Option<G>);
241
242impl<S, P, O, G> GeneralizedQuad<S, P, O, G> {
243 pub const fn new(subject: S, predicate: P, object: O, graph: Option<G>) -> Self {
245 Self(subject, predicate, object, graph)
246 }
247
248 pub const fn subject(&self) -> &S {
250 &self.0
251 }
252
253 pub const fn predicate(&self) -> &P {
255 &self.1
256 }
257
258 pub const fn object(&self) -> &O {
260 &self.2
261 }
262
263 pub const fn graph(&self) -> Option<&G> {
265 self.3.as_ref()
266 }
267
268 pub fn into_subject(self) -> S {
270 self.0
271 }
272
273 pub fn into_predicate(self) -> P {
275 self.1
276 }
277
278 pub fn into_object(self) -> O {
280 self.2
281 }
282
283 pub fn into_graph(self) -> Option<G> {
285 self.3
286 }
287
288 pub fn into_parts(self) -> (S, P, O, Option<G>) {
290 (self.0, self.1, self.2, self.3)
291 }
292
293 pub fn into_triple(self) -> (GeneralizedTriple<S, P, O>, Option<G>) {
295 (GeneralizedTriple(self.0, self.1, self.2), self.3)
296 }
297
298 pub fn map_subject<U>(self, f: impl FnOnce(S) -> U) -> GeneralizedQuad<U, P, O, G> {
300 GeneralizedQuad(f(self.0), self.1, self.2, self.3)
301 }
302
303 pub fn map_predicate<U>(self, f: impl FnOnce(P) -> U) -> GeneralizedQuad<S, U, O, G> {
305 GeneralizedQuad(self.0, f(self.1), self.2, self.3)
306 }
307
308 pub fn map_object<U>(self, f: impl FnOnce(O) -> U) -> GeneralizedQuad<S, P, U, G> {
310 GeneralizedQuad(self.0, self.1, f(self.2), self.3)
311 }
312
313 pub fn map_graph<U>(self, f: impl FnOnce(Option<G>) -> Option<U>) -> GeneralizedQuad<S, P, O, U> {
315 GeneralizedQuad(self.0, self.1, self.2, f(self.3))
316 }
317
318 pub fn with_graph(self, g: Option<G>) -> Self {
320 Self(self.0, self.1, self.2, g)
321 }
322
323 pub fn map_all<S2, P2, O2, G2>(
325 self,
326 s: impl FnOnce(S) -> S2,
327 p: impl FnOnce(P) -> P2,
328 o: impl FnOnce(O) -> O2,
329 g: impl FnOnce(Option<G>) -> Option<G2>,
330 ) -> GeneralizedQuad<S2, P2, O2, G2> {
331 GeneralizedQuad(s(self.0), p(self.1), o(self.2), g(self.3))
332 }
333
334 pub const fn as_ref(&self) -> GeneralizedQuad<&S, &P, &O, &G> {
336 GeneralizedQuad(&self.0, &self.1, &self.2, self.3.as_ref())
337 }
338}
339
340impl<S, P, O, G> GeneralizedQuad<&S, &P, &O, &G> {
341 pub fn cloned(&self) -> GeneralizedQuad<S, P, O, G>
343 where
344 S: Clone,
345 P: Clone,
346 O: Clone,
347 G: Clone,
348 {
349 GeneralizedQuad(self.0.clone(), self.1.clone(), self.2.clone(), self.3.cloned())
350 }
351
352 pub fn into_cloned(self) -> GeneralizedQuad<S, P, O, G>
354 where
355 S: Clone,
356 P: Clone,
357 O: Clone,
358 G: Clone,
359 {
360 GeneralizedQuad(self.0.clone(), self.1.clone(), self.2.clone(), self.3.cloned())
361 }
362
363 pub const fn copied(&self) -> GeneralizedQuad<S, P, O, G>
365 where
366 S: Copy,
367 P: Copy,
368 O: Copy,
369 G: Copy,
370 {
371 GeneralizedQuad(*self.0, *self.1, *self.2, self.3.copied())
372 }
373
374 pub const fn into_copied(self) -> GeneralizedQuad<S, P, O, G>
376 where
377 S: Copy,
378 P: Copy,
379 O: Copy,
380 G: Copy,
381 {
382 GeneralizedQuad(*self.0, *self.1, *self.2, self.3.copied())
383 }
384}
385
386impl<T> GeneralizedQuad<T, T, T, T> {
387 pub fn map<U>(self, mut f: impl FnMut(T) -> U) -> GeneralizedQuad<U, U, U, U> {
389 GeneralizedQuad(f(self.0), f(self.1), f(self.2), self.3.map(f))
390 }
391}
392
393impl GeneralizedQuad<LocalTerm, LocalTerm, LocalTerm, LocalTerm> {
394 pub fn try_into_quad(self) -> Result<Quad<Id, IriBuf, LocalTerm, Id>, GeneralizationError> {
396 let GeneralizedQuad(s, p, o, g) = self;
397 let s = local_term_to_id(s)?;
398 let p = local_term_to_iri(p)?;
399 let g = match g {
400 Some(t) => Some(local_term_to_graph_id(t)?),
401 None => None,
402 };
403 Ok(Quad(s, p, o, g))
404 }
405}
406
407fn local_term_to_id(t: LocalTerm) -> Result<Id, GeneralizationError> {
408 match t {
409 LocalTerm::BlankId(b) => Ok(Id::BlankId(b)),
410 LocalTerm::Named(Term::Iri(iri)) => Ok(Id::Iri(iri)),
411 LocalTerm::Named(Term::Literal(_)) => Err(GeneralizationError::LiteralSubject),
412 LocalTerm::Triple(_) => Err(GeneralizationError::TripleTermSubject),
413 }
414}
415
416fn local_term_to_iri(t: LocalTerm) -> Result<IriBuf, GeneralizationError> {
417 match t {
418 LocalTerm::BlankId(_) => Err(GeneralizationError::BlankPredicate),
419 LocalTerm::Named(Term::Iri(iri)) => Ok(iri),
420 LocalTerm::Named(Term::Literal(_)) => Err(GeneralizationError::LiteralPredicate),
421 LocalTerm::Triple(_) => Err(GeneralizationError::TripleTermPredicate),
422 }
423}
424
425fn local_term_to_graph_id(t: LocalTerm) -> Result<Id, GeneralizationError> {
426 match t {
427 LocalTerm::BlankId(b) => Ok(Id::BlankId(b)),
428 LocalTerm::Named(Term::Iri(iri)) => Ok(Id::Iri(iri)),
429 LocalTerm::Named(Term::Literal(_)) => Err(GeneralizationError::LiteralGraph),
430 LocalTerm::Triple(_) => Err(GeneralizationError::TripleTermGraph),
431 }
432}
433
434impl<S: IsSubject, P: IsPredicate, O: IsObject, G: IsGraph> From<Quad<S, P, O, G>> for GeneralizedQuad<S, P, O, G> {
435 fn from(q: Quad<S, P, O, G>) -> Self {
436 GeneralizedQuad(q.0, q.1, q.2, q.3)
437 }
438}
439
440impl<S1, P1, O1, G1, S2, P2, O2, G2> PartialEq<GeneralizedQuad<S2, P2, O2, G2>> for GeneralizedQuad<S1, P1, O1, G1>
441where
442 S1: PartialEq<S2>,
443 P1: PartialEq<P2>,
444 O1: PartialEq<O2>,
445 G1: PartialEq<G2>,
446{
447 fn eq(&self, other: &GeneralizedQuad<S2, P2, O2, G2>) -> bool {
448 self.0 == other.0
449 && self.1 == other.1
450 && self.2 == other.2
451 && match (&self.3, &other.3) {
452 (Some(a), Some(b)) => a == b,
453 (None, None) => true,
454 _ => false,
455 }
456 }
457}
458
459impl<S1, P1, O1, G1, S2, P2, O2, G2> PartialOrd<GeneralizedQuad<S2, P2, O2, G2>> for GeneralizedQuad<S1, P1, O1, G1>
460where
461 S1: PartialOrd<S2>,
462 P1: PartialOrd<P2>,
463 O1: PartialOrd<O2>,
464 G1: PartialOrd<G2>,
465{
466 fn partial_cmp(&self, other: &GeneralizedQuad<S2, P2, O2, G2>) -> Option<Ordering> {
467 match self.0.partial_cmp(&other.0) {
468 Some(Ordering::Equal) => match self.1.partial_cmp(&other.1) {
469 Some(Ordering::Equal) => match self.2.partial_cmp(&other.2) {
470 Some(Ordering::Equal) => match (&self.3, &other.3) {
471 (Some(a), Some(b)) => a.partial_cmp(b),
472 (Some(_), None) => Some(Ordering::Greater),
473 (None, Some(_)) => Some(Ordering::Less),
474 (None, None) => Some(Ordering::Equal),
475 },
476 cmp => cmp,
477 },
478 cmp => cmp,
479 },
480 cmp => cmp,
481 }
482 }
483}
484
485impl<S: RdfDisplay, P: RdfDisplay, O: RdfDisplay, G: RdfDisplay> fmt::Display for GeneralizedQuad<S, P, O, G> {
486 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
487 match self.graph() {
488 Some(graph) => write!(
489 f,
490 "{} {} {} {}",
491 self.0.rdf_display(),
492 self.1.rdf_display(),
493 self.2.rdf_display(),
494 graph.rdf_display()
495 ),
496 None => write!(f, "{} {} {}", self.0.rdf_display(), self.1.rdf_display(), self.2.rdf_display()),
497 }
498 }
499}
500
501impl<S: RdfDisplay, P: RdfDisplay, O: RdfDisplay, G: RdfDisplay> RdfDisplay for GeneralizedQuad<S, P, O, G> {
502 fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
503 match self.graph() {
504 Some(graph) => write!(
505 f,
506 "{} {} {} {}",
507 self.0.rdf_display(),
508 self.1.rdf_display(),
509 self.2.rdf_display(),
510 graph.rdf_display()
511 ),
512 None => write!(f, "{} {} {}", self.0.rdf_display(), self.1.rdf_display(), self.2.rdf_display()),
513 }
514 }
515}
516
517#[derive(Debug, Clone, PartialEq, Eq, Hash)]
528pub enum GeneralizedLocalTerm {
529 BlankId(BlankIdBuf),
531 Named(Term),
533 Triple(Box<GeneralizedTriple<GeneralizedLocalTerm>>),
536}
537
538impl GeneralizedLocalTerm {
539 pub const fn iri(iri: IriBuf) -> Self {
541 Self::Named(Term::Iri(iri))
542 }
543
544 pub const fn literal(literal: Literal) -> Self {
546 Self::Named(Term::Literal(literal))
547 }
548
549 pub fn triple(t: GeneralizedTriple<GeneralizedLocalTerm>) -> Self {
551 Self::Triple(Box::new(t)) }
553
554 pub const fn is_blank_id(&self) -> bool {
556 matches!(self, Self::BlankId(_))
557 }
558
559 pub const fn is_triple(&self) -> bool {
561 matches!(self, Self::Triple(_))
562 }
563
564 pub fn as_blank_id(&self) -> Option<&BlankId> {
566 match self {
567 Self::BlankId(b) => Some(b),
568 _ => None,
569 }
570 }
571
572 pub fn as_iri(&self) -> Option<Iri<&str>> {
574 match self {
575 Self::Named(Term::Iri(iri)) => Some(iri.as_ref()),
576 _ => None,
577 }
578 }
579
580 pub fn as_literal(&self) -> Option<LiteralRef<'_>> {
582 match self {
583 Self::Named(Term::Literal(l)) => Some(l.as_ref()),
584 _ => None,
585 }
586 }
587
588 pub fn as_triple(&self) -> Option<&GeneralizedTriple<GeneralizedLocalTerm>> {
590 match self {
591 Self::Triple(t) => Some(t),
592 _ => None,
593 }
594 }
595
596 pub fn try_into_local_term(self) -> Result<LocalTerm, GeneralizationError> {
598 match self {
599 Self::BlankId(b) => Ok(LocalTerm::BlankId(b)),
600 Self::Named(t) => Ok(LocalTerm::Named(t)),
601 Self::Triple(b) => {
602 let GeneralizedTriple(s, p, o) = *b;
603 let s = generalized_to_id(s, GeneralizationError::LiteralSubject)?;
604 let p = generalized_to_iri(p)?;
605 let o = o.try_into_local_term()?;
606 Ok(LocalTerm::triple(Triple(s, p, o)))
607 }
608 }
609 }
610}
611
612impl From<LocalTerm> for GeneralizedLocalTerm {
613 fn from(value: LocalTerm) -> Self {
614 match value {
615 LocalTerm::BlankId(b) => Self::BlankId(b),
616 LocalTerm::Named(t) => Self::Named(t),
617 LocalTerm::Triple(b) => {
618 let Triple(s, p, o) = std::sync::Arc::try_unwrap(b).unwrap_or_else(|arc| (*arc).clone());
619 let s = match s {
620 Id::Iri(iri) => Self::Named(Term::Iri(iri)),
621 Id::BlankId(b) => Self::BlankId(b),
622 };
623 let p = Self::Named(Term::Iri(p));
624 let o = Self::from(o);
625 Self::triple(GeneralizedTriple(s, p, o))
626 }
627 }
628 }
629}
630
631impl From<BlankIdBuf> for GeneralizedLocalTerm {
632 fn from(value: BlankIdBuf) -> Self {
633 Self::BlankId(value)
634 }
635}
636
637impl From<IriBuf> for GeneralizedLocalTerm {
638 fn from(value: IriBuf) -> Self {
639 Self::iri(value)
640 }
641}
642
643impl From<Literal> for GeneralizedLocalTerm {
644 fn from(value: Literal) -> Self {
645 Self::literal(value)
646 }
647}
648
649impl From<Term> for GeneralizedLocalTerm {
650 fn from(value: Term) -> Self {
651 Self::Named(value)
652 }
653}
654
655impl fmt::Display for GeneralizedLocalTerm {
656 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657 match self {
658 Self::BlankId(b) => b.fmt(f),
659 Self::Named(t) => t.fmt(f),
660 Self::Triple(t) => {
661 f.write_str("<<( ")?;
662 t.rdf_fmt(f)?;
663 f.write_str(" )>>")
664 }
665 }
666 }
667}
668
669impl RdfDisplay for GeneralizedLocalTerm {
670 fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
671 match self {
672 Self::BlankId(b) => b.rdf_fmt(f),
673 Self::Named(t) => t.rdf_fmt(f),
674 Self::Triple(t) => {
675 f.write_str("<<( ")?;
676 t.rdf_fmt(f)?;
677 f.write_str(" )>>")
678 }
679 }
680 }
681}
682
683impl __seal::Sealed for GeneralizedLocalTerm {}
687impl IsSubject for GeneralizedLocalTerm {}
688impl IsPredicate for GeneralizedLocalTerm {}
689impl IsObject for GeneralizedLocalTerm {}
690impl IsGraph for GeneralizedLocalTerm {}
691
692pub type FullyGeneralizedTriple = GeneralizedTriple<GeneralizedLocalTerm>;
694
695pub type FullyGeneralizedQuad = GeneralizedQuad<GeneralizedLocalTerm>;
697
698impl FullyGeneralizedTriple {
699 pub fn try_into_strict_triple(self) -> Result<Triple<Id, IriBuf, LocalTerm>, GeneralizationError> {
701 let GeneralizedTriple(s, p, o) = self;
702 let s = generalized_to_id(s, GeneralizationError::LiteralSubject)?;
703 let p = generalized_to_iri(p)?;
704 let o = o.try_into_local_term()?;
705 Ok(Triple(s, p, o))
706 }
707}
708
709impl FullyGeneralizedQuad {
710 pub fn try_into_strict_quad(self) -> Result<Quad<Id, IriBuf, LocalTerm, Id>, GeneralizationError> {
712 let GeneralizedQuad(s, p, o, g) = self;
713 let s = generalized_to_id(s, GeneralizationError::LiteralSubject)?;
714 let p = generalized_to_iri(p)?;
715 let o = o.try_into_local_term()?;
716 let g = match g {
717 Some(t) => Some(generalized_to_id(t, GeneralizationError::LiteralGraph)?),
718 None => None,
719 };
720 Ok(Quad(s, p, o, g))
721 }
722}
723
724fn generalized_to_id(t: GeneralizedLocalTerm, on_literal: GeneralizationError) -> Result<Id, GeneralizationError> {
725 match t {
726 GeneralizedLocalTerm::BlankId(b) => Ok(Id::BlankId(b)),
727 GeneralizedLocalTerm::Named(Term::Iri(iri)) => Ok(Id::Iri(iri)),
728 GeneralizedLocalTerm::Named(Term::Literal(_)) => Err(on_literal),
729 GeneralizedLocalTerm::Triple(_) => Err(match on_literal {
730 GeneralizationError::LiteralGraph => GeneralizationError::TripleTermGraph,
731 _ => GeneralizationError::TripleTermSubject,
732 }),
733 }
734}
735
736fn generalized_to_iri(t: GeneralizedLocalTerm) -> Result<IriBuf, GeneralizationError> {
737 match t {
738 GeneralizedLocalTerm::BlankId(_) => Err(GeneralizationError::BlankPredicate),
739 GeneralizedLocalTerm::Named(Term::Iri(iri)) => Ok(iri),
740 GeneralizedLocalTerm::Named(Term::Literal(_)) => Err(GeneralizationError::LiteralPredicate),
741 GeneralizedLocalTerm::Triple(_) => Err(GeneralizationError::TripleTermPredicate),
742 }
743}
744