Talk:Y combinator: Difference between revisions

→‎Comment on the overall task: edited, responded...
(→‎Comment on the overall task: edited, responded...)
Line 196:
For most languages it seems that this task is a joke, as the real use of the Y combinator is to apply recursion to a non-recursive function (often with recursion '''on variables''' otherwise not possible in that particular language) in order to get an output. In order to implement it, one requires recursion on either functions or lambda functions, as the expression of the Y conbinator requires it in all cases. By not allowing recursive state, this means that the definition of "Y (or fix) = x where x = f x" (in Haskell syntax) is not allowed as x is a variable state; indeed, for most strict languages this is not directly possible as it causes an infinite race and even with the addition of a lazy as in "let fix f = let rec x = lazy (f x) in x.force()" (F# syntax), this is still not possible in many more imperative type languages.
 
These languages may require something much more ugly such as follows (C# syntax):
<lang csharp> T rv = default(T); // (or other initial condition of the recursion)
rv = new Lazy(() => rv) // note: gets the '''future value''' (by reference) of rv
Line 204:
Note that the above code requires mutability of the 'rv' variable and also that it requires that the lambda retrieve the '''future version''' of rv. Most imperative type languages (and also functional languages other than Haskell) do have mutable variables '''but''' many (such as Rust) do not have the ability to refer to captured free variables future state (captured by value and not by reference as in C#). This would be the problem that this task would seek to address.
 
So, to break the infinite recursion when implementing a Y or Z combinator, most of these implementations introduce a recursive "Mu" type as in Haskell as follows:
<lang haskell>newtype Mu a = Roll { unroll :: Mu a -> a }
Line 213:
fac = fix $ \f n -> if (n <= 0) then 1 else n * f (n - 1)</lang>
 
Note that the above starts the joke, as all we have done is move the recursive state from the outside at the "fix" function to the inside in the recursive function as 'n' in this case, although it indeed does not use recursive state.
 
Part of the joke is that the above is useless: fix fac should produce Integer and an infinite race but it doesn't because the Haskell compiler knows category theory and the Lambda Calculus and can recognize (correctly) that this is an identity that just produces the 'f' function. In other words, it knows that we may as well have just written it as follows:
<lang haskell>fac n = if (n <= 0) then 1 else n * fac (n - 1)</lang>
 
which is '''the way one would normally write this recursively''' so that is what is effectively generated. In other wordwords, using fix had absolutely no purpose, although it is possible to do it in this case as it doesn't require closures!
 
Now other compilers (strict) (even most functional language ones) aren't so smart and either produce an infinite race or are smart enough to recognize that it would be one and error out, but aren't smart enough to recognize the identity. In the case of dynamically typed languages, this can work by use of the delay/lazy functionality as in the Scheme example above, but this doesn't work for statically typed languages.
 
So other versions of combinator (Z combinator, etc.) are used such as F# and Ocaml's Z combinator (perhaps among others) as follows (using Haskell signature syntax):
<lang haskell>Y :: (('a -> 'b) -> 'a -> 'b) -> 'b</lang>
 
or the Y combinator using recursive functions as used in C# and Rust (perhaps among others) as follows (again in Haskell signature syntax):
<lang haskell>Y :: (('a -> 'b) - ('a -> 'b)) -> ('a -> 'b)</lang>
 
However, the joke continues as these are just as useless when applied to a function that is already recursive.
 
The real purpose of the fixed point Y combinator is to implement recursion on functions that are not recursive, as in the "fibs" definition in the Haskell section as follows:
<lang haskell>fibs_ a = 0:1:(fix zipP a (tail a))
where
Line 240:
'''So I propose some changes/additions to this task as follows''':
 
1. clarifying that the form "fix f = f (fix f)" does or does not have recursive state and whether only the Lambda Calculus versions are acceptable as discussed above but obviously that "fix f = let x = f x in x" does have recursive state, which is not allowed.
 
2. Adding an objective to the task to use the 'fix'/'Y' function to generate a lazy list such as the above 'fibs' example.
 
Most languages have a built in "lazy" capability although it may be optional, but if not a non-thread safe version (which can reasonably easily be changed to a thread-safe version) can easily be generated as follows (for Go language):
<lang golang>type Lazy struct {
value *whatever_type_is_to_be_included // go doesn't have generics
Line 283:
}</lang>
 
Examples for languages capable of generating 'fibs' as per this algorithm would be truly useful and not a joke. -- [[User:GordonBGood|GordonBGood]] 15([[User talk:53GordonBGood|talk]]) 03:32, 1011 July 2016 (UTC)
 
: (1) Please sign your talk page submissions. (I have manually added a signature for you, which I think represents what you would have gotten if you had used the <nowiki>--~~~~</nowiki> wiki signature slug line.)
 
: : Thank you, forgot...
 
: (2) On this site, any task which specifies implementation details instead of desired result(s) is going to be (or contain) a joke. See also the [[Rosetta_Code:Add_a_Task|add a task]] page which gives some recommendations centered around the issues of choosing tasks which are useful in a "compare across language" context. --[[User:Rdm|Rdm]] ([[User talk:Rdm|talk]]) 16:03, 10 July 2016 (UTC)
 
: : Yes, I see your point; my issue arose because I actually need something like what I suggested as an additional requirement for one particular language (there may be others) and was frustrated that that particular language seems to be unable to do what I believe I require; whereas the required "fac" and "fib" examples are so trivial (as in a joke) that they can be implemented very easily in other ways not using a Y (or Z) combinator.
 
: : My purpose in the above sample code is not to specify implementation details, but merely to show that features required in order to accomplish my suggested result objective is possible for languages that don't have those features either built-in or available in a standard library. --[[User:GordonBGood|GordonBGood]] ([[User talk:GordonBGood|talk]]) 03:32, 11 July 2016 (UTC)
474

edits