Zuerst: Was wäre ein guter Name für diese Monade? Mir fällt nix ein. Mit meiner Plüsch-Eule (in Ermangelung einer Gummi-Ente) reden hat auch nix gebracht. Bitte helft!
Code: Alles auswählen
from functools import reduce
# Look, Ma! It's a monad!
def unit(v):
yield v
def bind(m, gen):
return lambda v: (u for w in m(v) for u in gen(w))
def either(*gens):
return lambda v: (u for gen in gens for u in gen(v))
def and_then(*gens):
return reduce(bind, gens, unit)
def nothing(_):
yield from ()
Code: Alles auswählen
from collections import namedtuple, ChainMap
from functools import singledispatch
from itertools import count, starmap
Variable = namedtuple('Variable', 'name')
class MetaVar(type):
def __getattr__(cls, name, counter=count()):
return Variable(name + str(next(counter)))
class Var(metaclass=MetaVar):
pass
def unify_variable(that, this):
def _(subst):
if this in subst:
yield from unify(subst[this], that)(subst)
else:
yield subst.new_child({this: that})
return _
@singledispatch
def unify_list(that, this):
return lambda _: ()
@unify_list.register(Variable)
def _(that, this):
return unify_variable(that, this)
@unify_list.register(list)
def _(that, this):
if len(this) != len(that):
return nothing
elif len(this):
return and_then(*starmap(unify, zip(this, that)))
else:
return unit
@singledispatch
def unify(this, that):
def _(subst):
if this == that:
yield subst
return _
@unify.register(Variable)
def _(this, that):
return unify_variable(that, this)
@unify.register(list)
def _(this, that):
return unify_list(that, this)
def resolve(goal):
return goal(ChainMap())
Code: Alles auswählen
def child(a, b):
return either(
unify([a, b], ['archimedes', 'bob']),
unify([a, b], ['fluffy', 'fifi']),
unify([a, b], ['daisy', 'fluffy']),
unify([a, b], ['athene', 'zeus']),
)
def descendant(a, c):
b = Var.b
return either(
child(a, c),
and_then(child(a, b), child(b, c)),
)
def human(a):
return either(
unify(a, 'socrates'),
unify(a, 'plato'),
unify(a, 'bob'),
)
def dog(a):
return unify(a, 'fifi')
def mortal(a):
b = Var.b
return either(
human(a),
dog(a),
and_then(descendant(a, b), either(human(b), dog(b))),
)
x = Var.x
y = Var.y
for each in resolve(mortal(x)):
print(each[x])
print()
for each in resolve(mortal('archimedes')):
print('yes.')
print()
for each in resolve(mortal('joe')):
print('yes.')
else:
print('no.')
Code: Alles auswählen
socrates
plato
bob
fifi
archimedes
fluffy
daisy
yes.
no.