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.
Мне нравится.