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
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
# Solution provided by GitHub user KrNor,
# assuming that math_sqrt can be used
def squarer(a, b):
    def process_new_value():
        if has_value(b):
            if get_value(b) < 0:
                error("square less than 0 -- squarer", get_value(b))
            else:
                set_value(a, math_sqrt(get_value(b)), me)
        else:
            if has_value(a):
                set_value(b, get_value(a) * get_value(a), me)
    def process_forget_value():
        forget_value(a, me)
        forget_value(b, 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 -- squarer", request)
    connect(a, me)
    connect(b, me)
    return me

a = make_connector()
b = make_connector()
squarer(a, b)
probe("a", a)
probe("b", b)
print(set_value(a, 3, "user"))
