вторник, 23 марта 2010 г.

Обратные связи

Язык F# в наследство от OCaml получил интересную возможность задавать рекуррентные отношения декларативно, как есть. Например, в моих сообщениях постоянно используется одна и та же система дифф-уров. Теперь ее можно переписать на F# следующим образом:

  let rec a = integF (lazy (- ka*a)) 100.0
  and b = integF (lazy (ka*a - kb*b)) 0.0
  and c = integF (lazy (kb*b)) 0.0
  and ka = 1.0
  and kb = 1.0

Это – работающий пример, где функция integF возвращает интеграл (как некое вычисление в монаде моделирования) по заданной производной и начальному значению. Здесь мы видим, что (1) переменные можно задавать произвольно без указания зависимости, (2) обратные связи задаются через явную ленивость. Фактически есть еще третий очень важный пункт: (3) компилятор сам следит за разрешимостью системы (в отличие от того же Haskell). Мне особенно нравится этот пункт, поскольку он делает подобный метод пригодным для широкого практического применения. Например, у нас имеется eDSL, а неискушенные пользователи задают свои системы. Компилятор сам все проверит и укажет на ошибку в случае необходимости. Неоценимое свойство.

Правда, в случае одной более сложной системы компилятор F# (v1.9.9.9) почему-то неправильно вывел переменные. Соответствующий bug report был отослан. Я думаю, что это – временное явление.

Рекуррентные отношения можно задавать и более хитрым способом, используя генераторы массивов:

  let smoothNI (x: Lazy<Dynamics<float>>) (t: Lazy<Dynamics<float>>) n (i: Dynamics<float>) =
   let rec s = [|
    for k = 0 to n-1 do
     if k = 0 then
      yield integ (lazy ((x.Value - s.[k]) / (t.Value / (float n)))) i
     else
      yield integ (lazy ((s.[k-1] - s.[k]) / (t.Value / (float n)))) i |]
   in s.[n-1]

Здесь возвращается функция (значение в монаде моделирования), которая называется экспоненциальной порядка n сглаживающей x по времени t с начальным значением i.

Мне нравится.