Re[32]: Вопрос к Vlad2: Nemerle & R#
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.03.06 01:03
Оценка:
Здравствуйте, eao197, Вы писали:

E>Кстати, если сравнить реализацию compile-time вычисления факториала на C++:

E>
E>template< int N >
E>struct Factorial {
E>    enum { value = N * Factorial< N-1 >::value };
E>};

E>template<>
E>struct Factorial< 1 > {
E>    enum { value = 1 };
E>};

E>template<>
E>struct Factorial< 0 > {};
E>

E>то мне кажется, что она получается в более функциональном стиле, что ли

Не, она получается запутанной и корявой.

Почему вычисление во время компиляции должно отличаться от того же самого в рантайме?

На Немерле тоже самое будет выглядить естественно, и просто так как будет просто использовать туже версию функции, что и при рантайм вычисления.
Вот код библиотеки содержащей макрос CompileTimeFactorial() и функцию Factorial().
using System;

macro CompileTimeFactorial(x : uint)
{
  // Приведение типов (второй  : ulong) требуется из-за ошибки в компиляторе :(
  <[ ($(Math.Factorial(x) : ulong) : ulong) ]>
}

public module Math
{
  public static Factorial(x : uint) : ulong
  {
    def Loop(acc : ulong, x : uint)
    {
      if (x <= 1) acc else Loop(acc * x, x - 1)
    }
    
    Loop (1UL, x)
  }
}

А вот применение того и другого:
using System.Console;

WriteLine(Math.Factorial(20));
WriteLine(Math.Factorial(0));
WriteLine(CompileTimeFactorial(0));
WriteLine(CompileTimeFactorial(1));
WriteLine(CompileTimeFactorial(7));
WriteLine(CompileTimeFactorial(20));

Вывод на констоль:
2432902008176640000
1
1
1
5040
2432902008176640000

Вот декомпиляция кода сгенерированного компилятором Немерла в C#:
private static void Main()
{
      Console.WriteLine(Math.Factorial(20));
      Console.WriteLine(Math.Factorial(0));
      Console.WriteLine((ulong) 1);
      Console.WriteLine((ulong) 1);
      Console.WriteLine((ulong) 0x13b0);
      Console.WriteLine((ulong) 0x21c3677c82b40000);
}

Если попытаться подставить в макрос или функцию отрицательное число:
using System.Console;

WriteLine(Math.Factorial(-1));
WriteLine(CompileTimeFactorial(-1));

то компилятор корректно сообщит об ошибке:

test-014.n:3:11:3:25: error: in argument #1 (x), needed a System.UInt32, got int: System.Int32 is not a subtype of System.UInt32 [simple require]
test-014.n:3:11:3:25: error: typing error in call
test-014.n:4:11:4:31: error: macro `CompileTimeFactorial' expects following list of arguments: (uint) got some 1 parameters [-1]

Жаль, правда, что по разному.

Попытка подсунуть в макрос динамическое значение тоже не пройдет:
using System.Console;

def x = 7;
WriteLine(CompileTimeFactorial(7));

выдаст:

test-014.n:4:11:4:31: error: macro `CompileTimeFactorial' expects following list of arguments: (uint) got some 1 parameters [x]


Можно написать макрос чуть сложнее. Тогда можно будет научить его вынимать константные значения.

ЗЫ

В общем-то оптимизация факториала смысла не имеет из-за малого объема вычислений (при больших значениях параметра он просто вызовет переполнение, а при малых количество итераций мизерно), но этот пример хорошо демонстрирует идеологию вычислений во время компиляции. А именно, то что во время вычислений во время компиляции можно использовать обычные фукнции используемые в рантайме.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.