The C++ fac
isn't really a function, but a struct which has a member function.
struct aaaa // Not its real name.
{
template<typename a, typename b>
auto operator()(a self, b n) const
{
}
};
The overloaded call operator hides some of the trickery that C++ performs in order to implement "lambda functions"
When you "call" fac
, what happens is
fac.operator() (fac, 3);
so the argument to the function isn't the function itself, but an object which has it as a member.
One effect of this is that the function's type (i.e. the type of operator()
) does not occur in the type of the operator()
function itself.
(The type of self
is the struct that defines the function.)
The template part isn't necessary for this to work; this is a non-generic version of the fac
"function":
struct F
{
int operator()(const F& self, int n) const
{
// ...
}
};
F fac;
fac(fac, 3);
If we keep the template and rename operator()
to applY
:
// The Y type
template<typename a>
struct Y
{
// The wrapped function has type (Y<a>, a) -> a
a applY(const Y<a>& self, a n) const
{
if(n < 1)
return 1;
else
return n * self.applY(self, n-1);
}
};
template<typename a>
a fac(a n)
{
Y<a> y;
return y.applY(y, n);
}
we see that your working Haskell program and your C++ program are very similar - the differences are mainly punctuation.
In contrast, in Haskell
fac2 self 0 = 1
fac2 self n = n * (self self $ n-1)
self
is a function, and fac2
's type would have to be
X -> Int -> Int
for some X
.
Since self
is a function, and self self $ n-1
is an Int, self
's type is also X -> Int -> Int
.
But what could X
be?
It must be the same as the type of self
itself, i.e X -> Int -> Int
.
But that means that the type of self
is (substituting for X
):
(X -> Int -> Int) -> Int -> Int
so the type X
must also be
(X -> Int -> Int) -> Int -> Int
so self
's type must be
((X -> Int -> Int) -> Int -> Int) -> Int -> Int
and so on, ad infinitum.
That is, in Haskell the type would be infinite.
Your solution for Haskell essentially explicitly introduces the necessary indirection that C++ generates through its structure with a member function.