def member(item, x):
    return (None if is_none(x)
            else x if item == head(x)
            else member(item, tail(x)))
def for_each_except(exception, fun, list):
    def loop(items):
        if is_none(items):
            return "done"
        elif head(items) is exception:
            return loop(tail(items))
        else:
            fun(head(items))
            return loop(tail(items))
    return loop(list)
def inform_about_value(constraint):
    return constraint("I have a value.")

def inform_about_no_value(constraint):
    return constraint("I lost my value.")
def has_value(connector):
    return connector("has_value")

def get_value(connector):
    return connector("value")

def set_value(connector, new_value, informant):
    return connector("set_value")(new_value, informant)

def forget_value(connector, retractor):
    return connector("forget")(retractor)

def connect(connector, new_constraint):
    return connector("connect")(new_constraint)
def make_connector():
    value = False
    informant = False
    constraints = None
    def set_my_value(newval, setter):
        nonlocal value, informant
        if not has_value(me):
            value = newval
            informant = setter
            return for_each_except(setter,
                                   inform_about_value,
                                   constraints)
        elif value != newval:
            error("contradiction", llist(value, newval))
        else:
            return "ignored"
    def forget_my_value(retractor):
        nonlocal informant
        if retractor is informant:
            informant = False
            return for_each_except(retractor,
                                   inform_about_no_value,
                                   constraints)
        else:
            return "ignored"
    def connect(new_constraint):
        nonlocal constraints
        if is_none(member(new_constraint, constraints)):
            constraints = pair(new_constraint, constraints)
        else:
            pass
        if has_value(me):
            inform_about_value(new_constraint)
        else:
            pass
        return "done"
    def me(request):
        if request == "has_value":
            return informant is not False
        elif request == "value":
            return value
        elif request == "set_value":
            return set_my_value
        elif request == "forget":
            return forget_my_value
        elif request == "connect":
            return connect
        else:
            error("unknown operation -- connector", request)
    return me
def multiplier(m1, m2, product):
    def process_new_value():
        if ((has_value(m1) and get_value(m1) == 0)
                or (has_value(m2) and get_value(m2) == 0)):
            set_value(product, 0, me)
        elif has_value(m1) and has_value(m2):
            set_value(product, get_value(m1) * get_value(m2), me)
        elif has_value(product) and has_value(m1):
            set_value(m2, get_value(product) / get_value(m1), me)
        elif has_value(product) and has_value(m2):
            set_value(m1, get_value(product) / get_value(m2), me)
        else:
            pass
    def process_forget_value():
        forget_value(product, me)
        forget_value(m1, me)
        forget_value(m2, me)
        process_new_value()
    def me(request):
        if request == "I have a value.":
            process_new_value()
        elif request == "I lost my value.":
            process_forget_value()
        else:
            error("unknown request -- multiplier", request)
    connect(m1, me)
    connect(m2, me)
    connect(product, me)
    return me
def constant(value, connector):
    def me(request):
        error("unknown request -- constant", request)
    connect(connector, me)
    set_value(connector, value, me)
    return me
def adder(a1, a2, sum):
    def process_new_value():
        if has_value(a1) and has_value(a2):
            set_value(sum, get_value(a1) + get_value(a2), me)
        elif has_value(a1) and has_value(sum):
            set_value(a2, get_value(sum) - get_value(a1), me)
        elif has_value(a2) and has_value(sum):
            set_value(a1, get_value(sum) - get_value(a2), me)
        else:
            pass
    def process_forget_value():
        forget_value(sum, me)
        forget_value(a1, me)
        forget_value(a2, me)
        process_new_value()
    def me(request):
        if request == "I have a value.":
            process_new_value()
        elif request == "I lost my value.":
            process_forget_value()
        else:
            error("unknown request -- adder", request)
    connect(a1, me)
    connect(a2, me)
    connect(sum, me)
    return me
display = lambda x: x
def probe(name, connector):
    def print_probe(value):
        display("Probe: " + name + " = " + str(value))
    def process_new_value():
        print_probe(get_value(connector))
    def process_forget_value():
        print_probe("?")
    def me(request):
        return (process_new_value()
                if request == "I have a value."
                else process_forget_value()
                if request == "I lost my value."
                else error("unknown request -- probe", request))
    connect(connector, me)
    return me
# (a+b)/2 = c is same as a+b = 2*c = s
def averager(a, b, c):
    s = make_connector()
    v = make_connector()
    constant(2, v)
    multiplier(v, c, s)
    adder(a, b, s)

a = make_connector()
b = make_connector()
c = make_connector()
averager(a, b, c)

probe("c", c)
probe("b", b)
probe("a", a)

set_value(a, 25, "user")
set_value(c, 125, "user")
forget_value(a, "user")
forget_value(c, "user")
set_value(a, 7, "user")
print(set_value(b, 13, "user"))
