Framework for self-referential data structures: ConsList and ConsTree​
​By Athina Kyriazi​
University of Patras
[Abstract: Is it possible to operate in Self-Referential Expressions? For which of those is it worth making framework? ConsList and ConsTree are two self referential types that are being introduced in this community post. It includes new function definitions (ex. constructors) and properly modified functions from the List and the Tree Framework in order to be able to operate on these types.]

Initialization


Introduction

Is it possible to operate on Self-Referential Expressions?

Issues

Can expressions like x={x,x} be interpreted from the computer and what result are we anticipating from it?
The result that we receive is the following:
In[]:=
x={x,x}
$RecursionLimit
:Recursion depth of 1024 exceeded during evaluation of {x,x}.
Out[]=
Hold[{x,x}]
and now is the point that we ask ourselves: Why?
Basically what we did is: we created an infinite search loop which goal was to define the symbol x
LOOP DISCRIPTION
x={x,x} -> Initialize symbol x with expression {x,x} ->Evaluate@ {x,x} : List of elements that kernel needs to evaluate -> Evaluate[x] -> Searching for the value of x -> x={x,x}
The kernel detects this loop and applies Hold to the {x,x} expression in order to prevent infinite evaluation

Hold solution

If we were to apply Hold on top of the expression, we would prevent its evaluation from the kernel. This way, we can execute the code:
In[]:=
x=Hold[{x,x}]
Out[]=
Hold[{x,x}]

Answer

Yes, with proper handling. Helpful tools: Hold, HoldFirst, HoldRest, HoldForm, HoldPattern, HoldAll

Are there any MEANINGFUL Self-Referential Expressions?

Examples

cons:=cons[cons]​​cons:=cons[x,cons]

Answer

By assuming: meaningful <=> can be applied to solve a problems
1. First approach: extending existing Data Structures that exist in the Wolfram Language, which already have the “meaningful” attribute
2. Second approach: introduce a new Data Structure and reasoning its existence with an application
In this project, the first approach is being followed. Although, some ideas of other self referential data structures are being displayed in the examples above, none of them reasons its existence, so they can’t be properly introduced.

List and ConsList

ConsList Definition

In order to create an infinite list, I need to store each time the element that is placed in a specific position and a reference to the next ConsList object.
-Expression form of the ConsList object:
ConsList[ ID, next ]
-Expression form of multiple ConsList objects (infinite list, one-sided infinite “chain” of ConsList objects):
ConsList[ ID1, ConsList[ ID2, ConsList[ ID3, ...]]]
1st attempt: infiniteOnes is a function that defines a cons symbol in its body with arguments 1 and infiniteOnes (not successful)
Calling infiniteOnes -> Evaluate[cons[1, infiniteOnes]] -> Evaluate[1] and Evaluate[infiniteOnes] -> Calling infiniteOnes
As a result we have an “infinite” infiniteOnes recursion which results cons to be a self referential data structure
In[]:=
infiniteOnes:=ConsList[1,infiniteOnes]
not successful
In[]:=
infiniteOnes
$RecursionLimit
:Recursion depth of 1024 exceeded during evaluation of ConsList[1,infiniteOnes].
Out[]=
Hold[ConsList[1,infiniteOnes]]
prevent loop with HoldRest : ConsList doesn’t evaluate its arguments except from the first one ( 1 can’t be further evaluated because its an atom, in case of 1+1 as first argument: {{1+1},2})
In[]:=
SetAttributes[ConsList,HoldRest]
successful
In[]:=
infiniteOnes
Out[]=
ConsList[1,infiniteOnes]

Controllable ConsList expansion - New function definitions

controllable ConsList expansion: (the following function ended up being introduced in the final framework)
Basic code features:
-applying evaluation on top of Hold overcomes the Hold attribute and lets the kernel evaluate the expression. In the following code, Evaluation is allowed until a certain extend which is specified by the variable n.
-n variable countdown
-while n!=1 Evaluation of the second argument is forced
-if n==1 ConsList element is return without influencing the default HoldRest attribute
In[]:=
ExpandConsList[ConsList[ID_,next_],n_]:=ConsList[ID,Evaluate[ExpandConsList[next,n-1]]]​​ExpandConsList[ConsList[ID_,next_],1]:=ConsList[ID,next]
In[]:=
ExpandConsList[infiniteOnes,5]
In[]:=
ExpandConsList[infiniteOnes,100]
In order to visualize the self reference between the ConsList objects we can use the following code (this is implemented by the function DisplayConsList which is included in the code of the project)
In[]:=
ExpandConsList[infiniteOnes,10]//ExpressionTree
Out[]=

Connection between ConsList and List - Existing List Framework extension

controllable ConsList expansion and conversion into a list:
Basic code features:
-!calling a function with “next” as argument! (implicit Hold overcome)
Although “next” isn’t evaluated in the ConsList[ID, next] expression, nothing prevents it from being evaluated when being an argument in another function
-Prepend method: known programming logic when working with recursion and list initialization ( takes care of the list order
toList[ConsList[ID_,next_],n_]:=Prepend[toList[next,n-1],ID]/;n>1​​toList[ConsList[ID_,next_],n_]:={ID}/;n==1​​toList[ConsList[ID_,next_],n_]:={}/;n<=0
In[]:=
toList[infiniteOnes,10]
Out[]=
{1,1,1,1,1,1,1,1,1,1}
The above function can be translated into a list-framework function. Therefore the above function isn’t used in the actual project. (Purpose: logic reasoning why extending existing list framework)

Tree and ConsTree

ConsTree Definition

In order to create an infinite tree, I need to store the node’s ID and a reference to the a list of the next ConsTree objects which can be referred to as leaves.
-Expression form of the ConsTree object:
ConsTree[ID, nextChildren] nextChildren: list of ConsTree elements
-Expression form of multiple ConsTree objects (infinite list, one-sided infinite “chain” of ConsList objects):
ConsTree[ID1.1, {ConsTree[ID2.1, {...}],ConsTree[ID2.2, {...}], ...}]
​
ConsTree type follows the way that Tree elements are defined in order to be compatible, with small alterations, with the built-in Tree functions (For detailed explanation on the HoldRest attribute: List and ConsList / ConsList Definition)
In[]:=
SetAttributes[ConsTree,HoldRest]
In[]:=
myTree=ConsTree[0,{ConsTree[1,{ConsTree[2,next],ConsTree[2,next]}],ConsTree[1,{ConsTree[2,next1],ConsTree[2,next]}],ConsTree[1,{ConsTree[2,next],ConsTree[2,next]}]}]
In order to create an infinite Tree, a pattern is needed (a rule which determines the next leaves based on the value of the source node). Therefore, f returns a list and applies a certain rule to each node.
In[]:=
NestConsTree[f_,initialID_]:=ConsTree[initialID,NestConsTree[f,#]&/@f[initialID]]
In[]:=
quickTree=NestConsTree[{2*#,3*#,4*#}&,1]
Out[]=
ConsTree[1,(NestConsTree[{2#1,3#1,4#1}&,#1]&)/@({2#1,3#1,4#1}&)[1]]

Connection between ConsTree and Tree - Extend the existing Tree Framework

Basic Idea of the ConsTree code mapping the extended built-in functions into each one of the leaves that source from each node
In order to find the connection of ConsTree and Tree, a function which replaces the head ConsTree with Tree so that the Tree form can be displayed as output + implicit evaluation of hold element (explained in more detail in a similar example : List and ConsList / Controllable ConsList expansion - New function definitions)
Because the project has as ConsTree constructor only the NestConsTree function
In[]:=
ConsTree/:RootTree[ConsTree[ID_,nextChildren_],n_]:=Tree[ID,RootTree[#,n-1]&/@nextChildren]​​ConsTree/:RootTree[ConsTree[ID_,nextChildren_],0]:=ID
In[]:=
myTree=ConsTree[0,{ConsTree[1,{ConsTree[2,next],ConsTree[2,next]}],ConsTree[1,{ConsTree[2,next1],ConsTree[2,next]}],ConsTree[1,{ConsTree[2,next],ConsTree[2,next]}]}]
In[]:=
quickTree=NestConsTree[{f[#],g[#],h[#]}&,1]
Out[]=
ConsTree[1,(NestConsTree[{f[#1],g[#1],h[#1]}&,#1]&)/@({f[#1],g[#1],h[#1]}&)[1]]
In[]:=
RootTree[quickTree,3]
Out[]=
In[]:=
RootTree[myTree,2]
Out[]=

ConsList

Construction

The following functions are used for the construction of ConsList objects:

InfiniteSteps

creates a ConsList object with all the positive powers of 2
creates a ConsList object with all the negative powers of 2
creates a ConsList object with all negative numbers

InputSequence

arbitrary sequence:seq[n]=seq[n-1]^2+seq[n-5]

Quick Access (ConsListRange, InfiniteSames)

1. Function Repository Reference: ConsListRange
2. Function Repository Reference: InfiniteSames

Manipulation

The following functions are used for the manipulation of ConsList objects:

Combination of the extended List-Framework

New functions

ExpandConsList, DisplayConsList, ConsListMapThread, NestConsList

Application Examples

Primes

Fibonacci Sequence

2D infinity

In this example, a ConsList object element is created which has as ID another ConsList object. As a result, one could imagine the final structure having 2 infinite “degrees of freedom”
Defining the variables that determine the expansion extend
Show 2 independent expansions with the help:
1.the symbol f acting as a function with one argument and NestConsList function which creates the internal ConsList elements
2.the external ConsList elements are created by ConsListRange[1,1] (basic nats ConsList)
Display internal ConsList expression
replace f with #^2 squaring each element in order to define the next one in the internal ConsList

ConsTree

Construction

The following function is used for the construction of ConsTree objects:

ConsNestTree

creates an infinite tree by applying the specified (1st argument) rule to each node, start node: 0

Manipulation

The following functions are used for the manipulation of ConsTree objects:

Combination of the extended Tree-Framework

Application Example

Letter Combinations

Conclusion

List problems - What ConsList offers?

1. Smaller code size (shorter and more compact expressions)
because one expression includes multiple lists
2. Infinite attribute ( Memory limitations )

Why self-reference instead of Iteration?

1. Functional programming approach
2. Smaller code size (shorter expressions)

Possible model extensions

The following parts of code are not included in the code of the project. These are just suggestion and different ways of approaching the consList type (utilize the flexibility of the model, don’t just stick with the above models)

Keywords

◼
  • infinite list
  • ◼
  • infinite tree
  • ◼
  • Hold / Evaluate
  • ◼
  • Self reference / Recursion
  • Acknowledgment

    This project wouldn’t be possible without the help of my mentors Christopher Wolfram and Bradley Klee. Sotiris Michos contributed as well. Special thanks also to Dr. Stephen Wolfram for assigning me this project. The other great part of this experience was having lots of peers to work with and a fun team for project meetings.

    References

    ◼
  • https://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf