end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

kanren for python による論理プログラミング (家系図の解析)

https://www.oreilly.co.jp/books/9784873118727/

上記url の 6章の写経の続き。

以下の家系図を定義し、「John」の父親(≠義父)を求めます

                           John─Megan
                            │                  
      ┌──────────┼─────────────┐
 William─Emma             David─Olivia                Adam─Lily
  ┌─┤            ┌─┬─┴─┬──┬──┐          │
Cris Stephanie    Wayne Tiffany Julie Neil Peter        Sopia
#!/usr/local/python3/bin/python3
# -*- coding: utf-8 -*-
import json
import kanren
from kanren import Relation, facts, run, conde, var, eq 

relation = \
    {"father": [{"John": "William"},
                {"John": "David"},
                {"John": "Adam"},
                {"William": "Chris"},
                {"William": "Stephanie"},
                {"David": "Wayne"},
                {"David": "Tiffany"},
                {"David": "Julie"},
                {"David": "Neil"},
                {"David": "Peter"},
                {"Adam": "Sophia"} ],
     "mother": [{"Megan": "William"},
                {"Megan": "David"},
                {"Megan": "Adam"},
                {"Emma": "Stephanie"},
                {"Emma": "Chris"},
                {"Olivia": "Tiffany"},
                {"Olivia": "Julie"},
                {"Olivia": "Neil"},
                {"Olivia": "Peter"},
                {"Lily": "Sophia"}
     ]
    }

    
def parent(x, y):
    return kanren.conde((father(x, y),), (mother(x, y),))

def grandparent(x, y):
    temp = var() 
    return kanren.conde((parent(x, temp), parent(temp, y))) 

def sibling(x, y): # 兄弟
    temp = var()
    return kanren.conde((parent(temp, x), parent(temp, y))) 

def uncle(x, y):
    temp = kanren.var()
    return kanren.conde((father(temp, x), grandparent(temp, y))) 
#    return conde((sibling(temp, x), parent(temp, y)))


def main():
#    with open('relationships.json') as f:
#        d = json.loads(f.read())
    d = relation

    father = kanren.Relation()
    mother = kanren.Relation()

    for item in d['father']:
        kanren.facts(father, (list(item.keys())[0], list(item.values())[0])) 

    for item in d['mother']: 
        kanren.facts(mother, (list(item.keys())[0], list(item.values())[0])) 

    x = var()
    output = run(0, x, (father, 'John', x))
    for item in output:
        print(item)


if __name__ == '__main__':
    main()

↑こう書くと、↓こう表示されます

$ ./foo.py 
Adam
David
William