Thread overview | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
March 13, 2015 Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Is it possible to run this code in compile-time? import std.stdio, std.functional; ulong fact(ulong n) { alias mfact = memoize!fact; return n < 2 ? 1 : n * mfact(n - 1); } void main() { writeln(fact(10)); } In CommonLisp variable *factorial-cache* available in CT, and RT. Moreover, in the compiler environment of your *factorial-cache* and RT. Thus we memoires as calculations in CT (constants), and RT. (eval-always (defparameter *factorial-cache* (make-hash-table)) (defun factorial (n) (if (< n 1) 1 (setf (gethash n *factorial-cache*) (* n (factorial (1- n))))))) (define-compiler-macro factorial (&whole whole n) (if (constantp n) (factorial n) whole)) |
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dennis Ritchie | On 13/03/2015 2:23 p.m., Dennis Ritchie wrote: > Is it possible to run this code in compile-time? > > import std.stdio, std.functional; > > ulong fact(ulong n) > { > alias mfact = memoize!fact; > return n < 2 ? 1 : n * mfact(n - 1); > } > > void main() { > > writeln(fact(10)); > } > > In CommonLisp variable *factorial-cache* available in CT, and RT. > Moreover, in the compiler environment of your *factorial-cache* and RT. > Thus we memoires as calculations in CT (constants), and RT. > > (eval-always > (defparameter *factorial-cache* (make-hash-table)) > (defun factorial (n) > (if (< n 1) > 1 > (setf (gethash n *factorial-cache*) (* n (factorial (1- n))))))) > > (define-compiler-macro factorial (&whole whole n) > (if (constantp n) (factorial n) whole)) Here is an example I have in my Developing with compile time in mind book[0]: size_t factorial(size_t n) pure { assert(n < 11); if (n == 0) { return 1; } else { return n * factorial(n - 1); } } static assert(factorial(5) == 120); Notice how it is in a static assert? Yeah that is at compile time. You could assign it to e.g. an enum. Or force it over using meta-programming. If you haven't already, I would strongly recommend that you read my book on the subject. [0] https://leanpub.com/ctfe |
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Rikki Cattermole | On Friday, 13 March 2015 at 02:38:18 UTC, Rikki Cattermole wrote:
> You could assign it to e.g. an enum. Or force it over using meta-programming.
And this code can be rewritten to D?
template <int n>
struct Factorial
{
enum { value = n * Factorial<n - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
int main()
{
constexpr auto x = Factorial<5>::value;
constexpr auto y = Factorial<7>::value;
}
|
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dennis Ritchie | On Friday, 13 March 2015 at 12:49:48 UTC, Dennis Ritchie wrote:
> On Friday, 13 March 2015 at 02:38:18 UTC, Rikki Cattermole wrote:
>> You could assign it to e.g. an enum. Or force it over using meta-programming.
>
> And this code can be rewritten to D?
>
> template <int n>
> struct Factorial
> {
> enum { value = n * Factorial<n - 1>::value };
> };
>
> template <>
> struct Factorial<0>
> {
> enum { value = 1 };
> };
>
> int main()
> {
> constexpr auto x = Factorial<5>::value;
> constexpr auto y = Factorial<7>::value;
> }
You can translate it directly:
template Factorial(int n)
{
static if (n == 0)
{
enum Factorial = 1;
}
else static if (n > 0)
{
enum Factorial = n * Factorial!(n - 1);
}
else
{
static assert(false, "n cannot be negative");
}
}
int main()
{
//Calculated at compile time
auto x = Factorial!5;
auto y = Factorial!7;
}
However, it's much easier to just write a function and decide whether you want to calculate its value at runtime or compile time.
int factorial(int n)
in
{
assert(n >= 0, "n cannot be 0");
}
body
{
return n == 0 ? 1 : n * factorial(n - 1);
}
void main()
{
//Evaluated at compile time
enum x = factorial(5);
//Evaluated at runtime
auto y = factorial(7);
}
|
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Friday, 13 March 2015 at 12:58:13 UTC, Meta wrote:
> On Friday, 13 March 2015 at 12:49:48 UTC, Dennis Ritchie wrote:
>> On Friday, 13 March 2015 at 02:38:18 UTC, Rikki Cattermole wrote:
>>> You could assign it to e.g. an enum. Or force it over using meta-programming.
>>
>> And this code can be rewritten to D?
>>
>> template <int n>
>> struct Factorial
>> {
>> enum { value = n * Factorial<n - 1>::value };
>> };
>>
>> template <>
>> struct Factorial<0>
>> {
>> enum { value = 1 };
>> };
>>
>> int main()
>> {
>> constexpr auto x = Factorial<5>::value;
>> constexpr auto y = Factorial<7>::value;
>> }
>
> You can translate it directly:
>
> template Factorial(int n)
> {
> static if (n == 0)
> {
> enum Factorial = 1;
> }
> else static if (n > 0)
> {
> enum Factorial = n * Factorial!(n - 1);
> }
> else
> {
> static assert(false, "n cannot be negative");
> }
> }
>
> int main()
> {
> //Calculated at compile time
> auto x = Factorial!5;
> auto y = Factorial!7;
> }
>
>
>
>
> However, it's much easier to just write a function and decide whether you want to calculate its value at runtime or compile time.
>
> int factorial(int n)
> in
> {
> assert(n >= 0, "n cannot be 0");
> }
> body
> {
> return n == 0 ? 1 : n * factorial(n - 1);
> }
>
> void main()
> {
> //Evaluated at compile time
> enum x = factorial(5);
>
> //Evaluated at runtime
> auto y = factorial(7);
> }
Thanks.
|
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dennis Ritchie | On Friday, 13 March 2015 at 12:49:48 UTC, Dennis Ritchie wrote: > On Friday, 13 March 2015 at 02:38:18 UTC, Rikki Cattermole wrote: >> You could assign it to e.g. an enum. Or force it over using meta-programming. > > And this code can be rewritten to D? > > template <int n> > struct Factorial > { > enum { value = n * Factorial<n - 1>::value }; > }; > > template <> > struct Factorial<0> > { > enum { value = 1 }; > }; > > int main() > { > constexpr auto x = Factorial<5>::value; > constexpr auto y = Factorial<7>::value; > } confusingly, D uses enum for named compile-time constants. http://ddili.org/ders/d.en/enum.html If you take Rikki's example and apply it to an enum(i.e, enum x = factorial(5); ) the program will fail to compile if it can't be computed at compile-time. |
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to weaselcat | On Friday, 13 March 2015 at 13:16:27 UTC, weaselcat wrote:
> On Friday, 13 March 2015 at 12:49:48 UTC, Dennis Ritchie wrote:
>> On Friday, 13 March 2015 at 02:38:18 UTC, Rikki Cattermole wrote:
>>> You could assign it to e.g. an enum. Or force it over using meta-programming.
>>
>> And this code can be rewritten to D?
>>
>> template <int n>
>> struct Factorial
>> {
>> enum { value = n * Factorial<n - 1>::value };
>> };
>>
>> template <>
>> struct Factorial<0>
>> {
>> enum { value = 1 };
>> };
>>
>> int main()
>> {
>> constexpr auto x = Factorial<5>::value;
>> constexpr auto y = Factorial<7>::value;
>> }
>
> confusingly, D uses enum for named compile-time constants.
> http://ddili.org/ders/d.en/enum.html
>
> If you take Rikki's example and apply it to an enum(i.e,
> enum x = factorial(5);
> )
>
> the program will fail to compile if it can't be computed at compile-time.
woops, walked away to get coffee before I submitted and got
beaten to the punch by a better answer : )
|
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | And you can somehow memoization stuff at compile time? |
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dennis Ritchie | On Friday, 13 March 2015 at 13:51:43 UTC, Dennis Ritchie wrote:
> And you can somehow memoization stuff at compile time?
If you want memoization at compile time I would suggest using the template version of Factorial as template instantiations are cached by the compiler. However, std.functional.memoize may work as well at compile time, I don't know.
|
March 13, 2015 Re: Memoization in compile-time | ||||
---|---|---|---|---|
| ||||
Posted in reply to weaselcat | On 03/13/2015 06:16 AM, weaselcat wrote: > confusingly, D uses enum for named compile-time constants. > http://ddili.org/ders/d.en/enum.html Actually, 'static' works as well. I have enumerated the cases here: http://ddili.org/ders/d.en/functions_more.html#ix_functions_more.CTFE <quote> For a function to be executed at compile time, it must appear in an expression that in fact is needed at compile time: - Initializing a static variable - Initializing an enum variable - Calculating the length of a fixed-length array - Calculating a template value argument </quote> Are there other cases that is worth adding to that list? Ali |
Copyright © 1999-2021 by the D Language Foundation