Defining a combinator that:
is defined as a lambda member without free variables, therefore, by definition, any combinator is already a lambda member,
you can define, for example, the structure of the list by writing:
Y = (list definition in lambda calculus) Y LIST = (list definition in lambda calculus) LIST Y LIST = (element insertion definition in lambda calculus)
Intuitively and using a fixed-point combinator, a definition is possible - consider \ = lambda:
- the list is either empty, and the next trailing element, for example
0 ; - or the list is formed by the element
x , which may be another list inside the previous one.
Since it was defined with a combinator - a fixed-point combinator - there is no need to run additional applications, the next abstraction is the lambda term itself.
Y = \f.\y.\xf (xy)
Now, calling it a LIST:
Y LIST = (*\f*.\y.\x.*f* (xy)) *LIST* -- applying function name LIST = \y.\x.LIST (xy), and adding the trailing element "0" LIST = (\y.\x.LIST (xy) ) 0 LIST = (*\y*.\x.LIST (x *y*) ) *0* LIST = \x.LIST (x 0), which defines the element insertion abstraction.
A fixed-point combinator Y or just a combinator allows you to consider the definition of LIST as a valid member without free variables, therefore, without the need for abbreviations.
Then you can add / insert elements, for example 1 and 2, by doing:
LIST = (\x.LIST (x 0)) 1 2 = = (*\x*.LIST (*x* 0)) *1* 2 = = (LIST (1 0)) 2 =
But here we know the definition of a list, so we expand it:
= (LIST (1 0)) 2 = = ((\y.\x.LIST (xy)) (1 0)) 2 = = ((*\y*.\x.LIST (x *y*)) *(1 0)*) 2 = = ( \x.LIST (x (1 0)) ) 2 =
Now by inserting element 2 :
= ( \x.LIST (x (1 0)) ) 2 = = ( *\x*.LIST (*x* (1 0)) ) *2* = = LIST (2 (1 0))
What can be expanded in case of a new insertion or simply left as is, due to the fact that LIST is a lambda member defined by a combinator.
Extension for future insertions:
= LIST (2 (1 0)) = = (\y.\x.LIST (xy)) (2 (1 0)) = = (*\y*.\x.LIST (x *y*)) *(2 (1 0))* = = \x.LIST (x (2 (1 0))) = = ( \x.LIST (x (2 (1 0))) ) (new elements...)
I am very glad that I was able to do this myself, but I am sure that there should be something good in defining a stack, heap or some more attractive structure. >
Trying to get an abstraction to insert / remove a stack - without a phased step:
Y = \f.\y.\xf (xy) Y STACK 0 = \x.STACK (x 0) STACK = \x.STACK (x 0)
To perform an operation on it, let's call an empty stack - allocation of a variable (:
stack = \x.STACK (x 0)
And again we will name this result so that we can put the elements:
stack = \x.STACK x (3 (2 (1 0))) // Removal -- POP STACK -> STACK POP = \s.(\ys (y (\t.\bb))) stack = POP stack = = ( \s.(\ys y (\t.\bb)) ) stack = = \y.(stack (y (\t.\bb))) = but we know the exact expansion of "stack", so: = \y.((\x.STACK x (3 (2 (1 0))) ) (y (\t.\bb))) = = \y.STACK y (\t.\bb) (3 (2 (1 0))) = no problem if we rename y to x (: = \x.STACK x (\t.\bb) (3 (2 (1 0))) = = \x.STACK x (\t.\bb) (3 (2 (1 0))) = someone guide me here, if i'm wrong = \x.STACK x (\bb) (2 (1 0)) = = \x.STACK x (2) (1 0) = = \x.STACK x (2 (1 0))
For what, I hope, we have element 3 .
I tried to get it myself, so if there were no restrictions on the lambda calculus, I did not follow, please indicate this.