Пример #1
0
        def add_handler(f):
            arg_names = inspect.getargspec(f).args[self.undispatched_args+unextracted_args:] #+1 for the asker
            self.handlers[filters][names].append((f, arg_names, extractions))

            if sum(extractions) == 1:
                extracted = [name for name, extract in zip(names, extractions) if extract]
                return term.simple(extracted[0], *arg_names)
            else:
                def throw(*args, **kwargs):
                    raise Exception("Dispatcher(f) only returns a function if there "
                        "is exactly one extracted argument.")
                return throw
Пример #2
0
        return result

    def set_repr(self, v, new_repr):
        self.update(updates.trivial(), v, repr_change=updates.become(new_repr))

    def reply(self, *args, **kwargs):
        reply = super(ContextUpdater, self).reply(*args, **kwargs)
        if self.Q is None:
            return reply
        responses = []
        for internal in self.internal.values():
            if self.changed[internal]:
                update = self.updates[internal]
                source = self.source[internal]
                responses.append(context_update(
                    source, 
                    update, 
                    representations.quote(self.current[internal])
                ))
        return reply.add(properties.combine(responses))

class UntaggedUpdateError(ValueError):
    pass

context_update = term.simple(
    "the value of [source] at the referenced question should be updated by applying [update], "
    "and the result should be represented as [repr]",
    "source", "update", "repr"
)
in_question = term.simple("the object referred to as [s] in the referenced question", "s")
Пример #3
0
from frozendict import frozendict
import functions
import lists
import termtypes
from termtypes import is_type

from ipdb import set_trace as debug


cons = T.dict_cons
empty = T.empty_dict

dict_type = termtypes.new_type("the type of dictionaries")
termtypes.set_types(dict_type, cons, empty)

image = term.simple("the function that maps a dictionary to the image of [k] in that dictionary", "k")

@getter(image.head, cons.head)
def cons_image(asker, k, key, value, other):
    if booleans.ask_firmly(asker, builtins.equal(k, key)):
        return asker.reply(answer=value)
    else:
        return asker.ask_tail(
            fields.get_field(image(k), other), 
            handler=asker.pass_through(not_found.head)
        )

@getter(image.head, empty.head)
def image_empty(asker, k):
    return asker.reply(value=not_found())
Пример #4
0
from ipdb import set_trace as debug
import term
from term import as_head, Term as T
import database
import askers
from dispatch import Dispatcher
import handlers
import properties
from builtins import builtin
import fields
import relayer
import updates
import context

state = term.simple("a state of the interpeter where [history] maps "
    "strings to the user's historical response to those strings, "
    "and where [computation] is invoked to handle computations",
    'history', 'computation')

history = fields.named_binding(
    "the function that maps an interpreter state to the history of commands that "
    "have been entered in that state",
    state.head,
    'history'
)

handler = fields.named_binding(
    "the function that maps an interpreter state to the computation invoked "
    "to handle questions in that state",
    state.head,
    'computation'
)
import term
from memoization import memoize
import properties
import fields
from frozendict import frozendict
import askers
import termtypes

#Representing terms--------------------------------

#TODO I could probably make Representation a function,
#then make a decorator that turns any such function into a "held"
#version...


quoted_term = term.simple("a term with head [head] head and bindings [bindings]",
        'head', 'bindings')
term_type = termtypes.new_type("the type of terms")
termtypes.set_type(term_type, quoted_term)

head = fields.named_binding(
    "the function that maps a term to its head",
    quoted_term.head,
    'head'
)

bindings = fields.named_binding(
    "the function that maps a term to its bindings",
    quoted_term.head,
    'bindings'
)
Пример #6
0
    def __init__(self, question, other=None):
        if other is None:
            other = properties.trivial()
        self.other = other
        self.question = question

    def add(self, property):
        return Query(question=self.question, other=properties.both(property, self.other))

    def quote(self):
        return T("a query with question [question] and requested properties [properties]",
                  question=self.question, properties=self.other)

#Replies----------------------

answer_is = term.simple("the requested answer is [A]", "A")

@term.as_head("answering question [Q]")
def answering(Q):
    return term.MetaTerm(answering.head, Q=Q)

class Reply():

    def __init__(self, value=None, answer=None, question=None):
        self.question = question
        if value is None:
            value = properties.trivial()
        if answer is not None:
            value = properties.both(answer_is(answer), value)
        self.value = value
Пример #7
0
def new_type(head, *args):
    result = term.simple(head, *args)
    set_type(meta_type, result)
    known_types.add(result)
    return result
Пример #8
0
def is_type(t):
    def set_by_head(f):
        set_type(t, f)
        return f
    return set_by_head

#NOTE using t() so that I can have parametrized types later
#but for this function it would be more natural to just pass in the constructed type
#I think this may bite me at some point
def set_type(t, head):
    if hasattr(head, 'head'):
        head = head.head
    @typesetter(head)
    def return_type(asker):
        return asker.reply(answer=t())
    return head

def set_types(t, *heads):
    return [set_type(t, head) for head in heads]

known_types = set()

def new_type(head, *args):
    result = term.simple(head, *args)
    set_type(meta_type, result)
    known_types.add(result)
    return result

meta_type = term.simple("the type of types")
new_type(meta_type.head)
Пример #9
0
#object: the object on which we are getting the field

setter = Dispatcher("setter", ("field", "object", "new_value"))
#object: the object on which we are setting the field
#new_value: the new value to which we are setting the field

#TODO think about properties affecting field retrieval...
#(e.g. we might be counting accesses, or have normative properties true of children...)

#TODO I should probably implement properties as boolean-valued fields

#FIXME if an object is in a reducible form, like an update or held question,
#then an access to its modifiers may not return the "real" modifiers.
#It seems worth thinking more about avoiding errors that that could cause.

field_not_found = term.simple("the referenced field wasn't found on the referenced object")

#TODO should call .explain more often...
#FIXME should cache the values of fields probably? Either as properties or by id.
#FIXME it seems like their should really just be a "cached" decorator?
#that operates at the meta level...
@builtin("what is the value of [field] of [object]?")
def get_field(asker, field, object):
    reply = getter.dispatch(asker, field, object)
    if reply is None:
        reply = asker.reply()
    if not reply.has_answer():
        reply.add(field_not_found())
    return reply

def get(asker, field, object):
Пример #10
0
    if convert.check_hard(asker, lists.is_empty(), visible_children):
        return asker.reply(answer=updates.update(is_pointer_now(), object))
    else:
        result = updates.update(has_pointer_now(), object)
    result = updates.update(
        updates.apply_to(
            fields.compose(visible_children(), lists.last_element()),
            add_pointer_to_bottom()
        ), 
        result
    )
    return asker.reply(answer=result)

#Adding children------------------------

children_on_expanded = term.simple("when expanded, should be given children from [bindings]", "bindings")

@updates.translator(children_on_expanded.head, toggle_expanded.head)
def add_children_on_expanded(asker, old, new, bindings):
    children = []
    for p in lists.iterator(asker, lists.from_dict(bindings)):
        k = asker.ask(fields.get_field(first(), p)).firm_answer
        v = asker.ask(fields.get_field(second(), p)).firm_answer
        prefix = strings.string_concat(k, T.from_str(": "))
        new_node = node_from_term(asker, v)
        new_node = updates.update(
            updates.apply_to(headline(), strings.prepend_str(prefix)),
            new_node
        )
        children.append(new_node)
    return asker.reply(answer=updates.update(
Пример #11
0
from dispatch import Dispatcher
import term
from term import Term as T
from ipdb import set_trace as debug

builtin = Dispatcher("builtin", ("question",))

#FIXME this should probably get taken over by dictionaries...
@builtin("what is a value bound to the key [key] in the bindings [bindings]?")
def lookup(asker,bindings,key):
    return searcher.dispatch(asker,bindings,key)

searcher = Dispatcher("searcher", ("bindings", "key"))

@searcher(T.dict_cons.head)
def simple_lookup(asker, search_key, key, value, other):
    are_equal = asker.ask(equal(key, search_key)).answer
    #FIXME should avoid these cyclic imports
    import convert
    if are_equal is not None and convert.to_bool(asker, are_equal):
        return asker.reply(answer=value)
    else:
        return asker.ask_tail(lookup(other, search_key))

equal = term.simple("are [a] and [b] equal?", "a", "b")
Пример #12
0
import askers
import term
from term import Term as T
import properties

class Counter(askers.BaseAsker):

    def __init__(self, *args, **kwargs):
        super(Counter, self).__init__(*args, **kwargs)
        self.cost = 1

    def reply(self, *args, **kwargs):
        result = super(Counter, self).reply(*args, **kwargs)
        return result.add(queries(T.from_int(self.cost)))

    def process_response(self, response, *args, **kwargs):
        if response.head == queries.head:
            #TODO could easily do this inside the system
            self.cost += response['k'].to_int()
            return properties.trivial()
        else:
            return super(Counter, self).process_response(response, *args, **kwargs)

queries = term.simple("[k] queries were posed while answering", 'k')
Пример #13
0
    return asker.reply(answer=representations.quote(k))

@interpreter(parsing.make_str_expr.head)
def interpret_str(asker, view, s):
    return asker.reply(answer=representations.quote(s))

@interpreter(parsing.make_list_expr.head)
def interpret_list(asker, view, l):
    #TODO if I had better mapping, this would be fine...
    #for now I have to do it in this terrible way...
    result = representations.make(T.empty_list.head)
    for x in reversed(list(lists.iterator(asker, l))):
        result = representations.make(T.cons.head, head=x, tail=result)
    return asker.reply(answer=result)

should_print = term.simple("the referent of [s] should be printed in the referenced view", "s")
should_dispatch = term.simple("the head of [x] should be printed and its bindings promoted "
        "in the referenced view", "x")
should_return = term.simple("[x] should be returned "
        "if the user interacts with the referenced view", "x")
should_assign = term.simple("[s] should refer to [x] in future interactions with the "
        "referenced view", "s", "x")

#TODO this is a duplicate of run_arg, I should generalize them
def interpret_arg(name):

    def make_interpreted_arg(f):

        arg_names = inspect.getargspec(f).args
        run_index = arg_names.index(name)
Пример #14
0
    T.simple_string.head,
    'list'
)

@is_type(string_type)
@literalizer("the string formed by concatenating [a] with [b]")
def concat(asker, a, b):
    return to_str(asker, a) + to_str(asker, b)


#Converting to chars------------------------------

def to_char(asker, c):
    if c.to_char() is not None:
        return c.to_char()
    result = char_literalizer.dispatch(asker, c)
    if result is not None:
        return result
    else:
        k = asker.ask_firmly(ascii_code(c))
        return chr(ints.to_int(k))

char_literalizer = Dispatcher("character literalizer", ("char",))

@is_type(char_type)
@char_literalizer(T.simple_char.head)
def literalize_simple_char(asker, x):
    return chr(ints.to_int(asker, x))

ascii_code = term.simple("what is the ascii code of the character [c]?", "c")