📜 ⬆️ ⬇️

Fixed point combinator

When I was first asked if there could be a function like Func<Func<T,T>,T> without using constructions like default (T) he plunged me into deep cognitive dissonance.
How can there be a function that has nowhere to take values? About the obvious option
T Fix<T>(Func<T,T> func){
return func(Fix(func));
}
I could not even think. Is it possible to do such a function? It will be called endlessly and will not work. In languages ​​like C #, such a construction will actually cause looping, but it can work in languages ​​like python or haskel. Now there will be some Haskell code, I hope the syntax will be more or less clear to everyone.
The simplest example:
fix f = f( fix f)
const42 x = 42
print (fix const42) -- , ?
If we expand the challenge, we will see that the following chain of calculations takes place:
fix const42 -> const42 ( fix const42) -> 42
The last transition is due to the fact that we do not need a function argument to calculate its value.
The question arises: if the function will depend on its argument, then the calculation will not stop, then how should we be?
Well, do not stop, okay. If the value is not used, then it should not be calculated, thanks to the laziness of Haskell.
: Is the function of adding an item to the head of the list. For example: 1:[2,3] = [1,2,3], n:[] = [n]

Consider the fix (1:) function. It returns a list that will obviously be infinite, but you can still use it.
take 3 (fix (1:)) -> take 3 (1:fix (1:)) -> 1:take 2 (fix (1:)) -> 1:(1:take 1 (fix (1:)))
-> 1:(1:(1:take 0 (fix (1:)))) -> 1:(1:(1:[])) -> 1:(1:[1]) -> 1:[1,1] -> [1,1,1]
So simply we got the result from the function that uses its parameter. We even created a useful thing:
repeat n = fix (n:) - Generate an infinite list of one repeating element.
Infinity is not a vice, the main thing is that somewhere, still inside or outside, the chain of calculations is broken. What constructions can break the chain?
Up to this point, we assumed that the function type for fix is ​​a significant type. But why don't we start using a higher order function ? Let's try a traditional example:
factCore f = \x -> if x == 0 then 1 else x * f (x-1)
Then the fix factCore function will be an ordinary factorial. In fact, each time instead of the function f, the factCore function will be substituted, which is why everything will become extremely similar to ordinary recursion.

Let's try something more complicated. For example, create all sequences of length k consisting of numbers from 1 to n, moreover, so that there are not two adjacent identical numbers. The task is sucked from the finger, but nonetheless.
allDiffCore nf = \k cond -> if k == 1 then map (\x->[x]) $ filter cond [1..n] else concat $ map (\x -> map (x:) (f (k-1) (/=x)) ) ( filter cond [1..n])
sequences nk = fix (allDiffCore n) k (\x->True)
Small explanations:
filter is a function that takes two parameters: conditions and a list. Returns a list of objects that satisfy the condition.
/= - ordinary "not equal". Such is the very mathematical record.
concat is a function that combines the list of lists into one list.
At each step, we take several suitable elements and set a function that determines whether the next element fits. With this pattern, you can generate many different sequences. For example, to get ever-increasing sequences, it is enough to change the part responsible for the filtering function, that is, replace (/ = x) with (> x).

And now the task is to think: how to write a function that will solve the problem of queens on an n * n size chessboard?
As you have already noticed, the use of the fix function (by the way, it is a special case of the fixed point combinator) avoids direct recursion in functions, which can be useful, for example, in lambda calculus, since ordinary recursion cannot be used there.
')
As a bonus, I offer a certain, strongly trimmed fixed point combinator, for c #:
public static Func<T1, T2> Fix<T1, T2>(Func<Func<T1, T2>, Func<T1, T2>> f)
{
// ,
// .

return f(x => Fix(f)(x));
}
And further use:
var fact = Fix< int , int >(self => x =>
{
if (x == 0)
return 1;
return x * self(x - 1);
});
var result = fact(5); // 120

Source: https://habr.com/ru/post/79713/


All Articles