compute-cplを読む
Gaucheのclass.cより引用.
/* * compute-cpl */ ScmObj Scm_ComputeCPL(ScmClass *klass) { ScmObj seqh = SCM_NIL, seqt = SCM_NIL, ds, dp, result; /* a trick to ensure we have <object> <top> at the end of CPL. */ ds = Scm_Delete(SCM_OBJ(SCM_CLASS_OBJECT), klass->directSupers, SCM_CMP_EQ); ds = Scm_Delete(SCM_OBJ(SCM_CLASS_TOP), ds, SCM_CMP_EQ); ds = Scm_Append2(ds, SCM_LIST1(SCM_OBJ(SCM_CLASS_OBJECT))); SCM_FOR_EACH(dp, klass->directSupers) { if (!Scm_TypeP(SCM_CAR(dp), SCM_CLASS_CLASS)) Scm_Error("non-class found in direct superclass list: %S", klass->directSupers); if (SCM_CAR(dp) == SCM_OBJ(SCM_CLASS_OBJECT) || SCM_CAR(dp) == SCM_OBJ(SCM_CLASS_TOP)) continue; SCM_APPEND1(seqh, seqt, SCM_CLASS(SCM_CAR(dp))->cpl); } SCM_APPEND1(seqh, seqt, Scm_ObjectClass.cpl); SCM_APPEND1(seqh, seqt, ds); result = Scm_MonotonicMerge1(seqh); if (SCM_FALSEP(result)) Scm_Error("discrepancy found in class precedence lists of the superclasses: %S", klass->directSupers); return Scm_Cons(SCM_OBJ(klass), result); }
trick関係っぽいのとエラーチェックを取り除くと
/* * compute-cpl */ ScmObj Scm_ComputeCPL(ScmClass *klass) { ScmObj seqh = SCM_NIL, seqt = SCM_NIL, ds, dp, result; ds = klass->directSupers; SCM_FOR_EACH(dp, klass->directSupers) { SCM_APPEND1(seqh, seqt, SCM_CLASS(SCM_CAR(dp))->cpl); } SCM_APPEND1(seqh, seqt, ds); result = Scm_MonotonicMerge1(seqh); return Scm_Cons(SCM_OBJ(klass), result); }
こんな感じ?
SCM_APPEND1
はgauche.hに,Scm_Delete
,Scm_Append2
,Scm_MonotonicMerge1
はlist.cに定義されている.
直接スーパークラスのCPLのリストに直接スーパークラスのリストをappendしてmerge.mergeの挙動は大まかにこんな感じ.
(monotonic-merge '((a b) (c d))) ; => (a b c d) (monotonic-merge '((a b) (c b))) ; => (a c b) (monotonic-merge '((a c) (b c))) ; => (a b c) (monotonic-merge '((a b) (b a))) ; => #f
このmergeがアルゴリズムの核な気がする.そしたらMonotonic Mergeのコメントの所に
* The algorithm is used in C3 linearization of class precedence * calculation
と書いてあった.Scm_MonotonicMerge1
の中身はややこしそうである.うーむ.