Log In Sign Up

Evolving Recursive Definitions with Applications to Dynamic Programming

Inspired by computability logic<cit.>, we refine recursive function definitions into two kinds: blindly-quantified (BQ) ones and parallel universally quantified (PUQ) ones. BQ definitions corresponds to the traditional ones where recursive definitions are not evolving. PUQ definitions are evolving in the course of computation, leading to automatic memoization. In addition, based on this idea, we propose a new, high-level object-oriented language.


page 1

page 2

page 3

page 4


A right-to-left type system for mutually-recursive value definitions

In call-by-value languages, some mutually-recursive value definitions ca...

Predicate Logic with Definitions

Predicate Logic with Definitions (PLD or D-logic) is a modification of f...

On Kinds of Indiscernibility in Logic and Metaphysics

Using the Hilbert-Bernays account as a spring-board, we first define fou...

let (rec) insertion without Effects, Lights or Magic

Let insertion in program generation is producing code with definitions (...

A Scheme-Driven Approach to Learning Programs from Input/Output Equations

We describe an approach to learn, in a term-rewriting setting, function ...

Recurrence extraction and denotational semantics with recursive definitions

With one exception, our previous work on recurrence extraction and denot...

Unboxing Mutually Recursive Type Definitions in OCaml

In modern OCaml, single-argument datatype declarations (variants with a ...

1 Introduction

The theory of recursive functions provides a basis for popular functional/imperative languages such as ML, Java and Javascript. It includes operations of composition, recursion, . Although the theory is quite expressive, it does not support automatic memoization and dynamic programming in a high-level way. As a consequence, dynamic programming is known to be cumbersome, as it requires the programmer to write extra, messy code to deal with memoization. In other words, it is a low-level approach.

In this paper, we propose a high-level approach to this problem. The idea is based on extending recursive definitions with some evolutionary features, which we call evolving recursive definitions. This idea comes from the recent important work called Computability Logic(CoL). See for its details[1].

2 Two Interpretations of

There are two different ways to interpret

where is an expressions.

  • The interpretation is the following: the above is true if it is true for all terms, i.e.,

  • The interpretation is the following: the above is true if it is true independent of . This is a subtle concept and can be viewed as an parallel interpretation. Note that this definition cannot be expanded.

In the sequel, we use instead of to denote parallel universal quantifier. Now the difference is the following:

Evaluating with respect to has the following intended semantics: create , evaluate and then discard .

In contrast, evaluating with respect to has the following intended semantics: create , evaluate and then do not discard .

Thus, definitions are evolving and intended to perform automatic memoization. This is a novel feature which is not present in traditional recursive definitions. On the other hand, the blind interpretation is the one that is used in traditional recursive definition.

3 Fibonacci with Memoization

In the traditional approach, function evaluation is based on the blind quantification. For example, a function is specified as:

Note that the third definition is a blind-quantified definition in [1] – means that it is true independent of .

Now, to compute , our machine temporarily creates the following new instances in the course of evaluation and discards them after.

To support (top-down) automatic memoization, all we have to do is to replace by .

In the sense of [1], PUQ definitions require to generates new instances of the existing function definitions and adds them permanently in front of the program. These new instances play a role similar to automatic memoization.

For example, a function can be specified as:

Note that the third definition is compressed and needs to be expanded during execution. For example, to compute , the above definition evolves/expands to the following

One consequence of our approach is that it supports dynamic programming.

4 The Language

The language is a version of the core functional languages — also one of recursive functions — with PUQ expressions. It is described by - and -rules given by the abstract syntax as follows: In the abstract syntax, and denote the expressions and the definitions, respectively. In the rules above, is a constant, is a variable, is a term which is either a variable or a constant. is called a program in this language.

Following the traditional approach for defining semantics [3], we will present the semantics of this language, essentially an interpreter for the language, as a set of rules in Definition 1. The evaluation strategy assumed by these rules is an eager evaluation. Note that execution alternates between two phases: the evaluation phase defined by eval and the backchaining phase by bc.

In the evaluation phase, denoted by , the machine tries to evaluate an expression from the program to get a value and an evolved definition . The rules (7) – (10) are related to this phase. For instance, if is a function call , the machine first evaluates all of its arguments and then looks for a definition of in the program in the backchaining mode (Rule 6).

The rules (1) – (6) describe the backchaining mode, denoted by . In the backchaining mode, the machine tries to evaluate a function call by using the function definition in the program . is the value after evaluation and is what evolves to. takes care of the BQ definitions and takes care of the PUQ ones.

Definition 1.  Let be an expression and let be a program. Then the notion of evaluating to a value and getting a new definition — is defined as follows:

  • if % switch to evaluation mode.

  • if % memoization.

  • if % memoization.

  • if . provided that is the first matching declaration.

  • if . % argument passing to and . % blind quantification

  • if % argument passing to and . % parallel universal quantification

  • if . % switch to backchaining by making a copy of for a function call.

  • if and . % evaluate the arguments first.

  • . % is always a success.

  • . % A success if is a constant.

5 Object-Oriented Programming

Evolving definitions in the previous section perform sequential search for a function definition. This is a slow process! We can speed up this search by permitting locations for a set of function definitions. The addition of locations makes it possible to provide a direct lookup of a function.

For example, assume that is stored at a location . Then can be rewritten as:

Now consider an expression . The machine creates two instances at run time.

Note that the above is nothing but an object-oriented programming in a distilled form. That is, in object-oriented terms, are regular objects and is a class object. Our language has some interesting features:

  1. Instances are created lazily and automatically.

  2. As we will see later, it supports nested objects.

  3. Class is not a primary means for creating an object: objects can be created without introducing its class.

Finally, note that adding imperative features to our languages poses no problem, still leading to a very concise code.

6 Nested objects

Consider an object definition of the form

For speedup, the method within an object can be further refined to

Now each call to must be of the form . Note that our language supports a novel nested object-oriented programming. Nested objects are quite useful for further speedup as well as clustering objects. We will look into this in the future.

Finally, our language is clearly influenced. by computability logic web[1, 2] (CoLweb) which is a promising approach to reaching general AI. Ideas in this paper – class agents and nested agents – will be useful for organizing agents and their knowledgebases in CoLweb.


  • [1] G. Japaridze, “Introduction to computability logic”, Annals of Pure and Applied Logic, vol.123, pp.1–99, 2003.
  • [2] G. Japaridze, “Sequential operators in computability logic”, Information and Computation, vol.206, No.12, pp.1443-1475, 2008.
  • [3]

    D. Miller, “A logical analysis of modules in logic programming”, Journal of Logic Programming, vol.6, pp.79–108, 1989.