2015-07-22 2 views
-2

У меня есть этот код в VBA (зацикливание через массив а() типа двойного):F # хитрым рекурсивный алгоритм

bm = 0          'tot 
    b = 0          'prev 
    For i = 24 To 0 Step -1 
     BP = b         'prevprev = prev 
     b = bm         'prev = tot 
     bm = T * b - BP + a(i)     'tot = a(i) + T * prev - prevprev 
    Next 
    p = Exp(-xa * xa) * (bm - BP)/4   '* (tot - prevprev)/4 

Я ставлю это в F #. Очевидно, я мог бы использовать массив и изменяемые переменные для воссоздания VBA. И, может быть, это пример правильного времени использования mutable, о котором я видел. Но почему бы не попытаться сделать это самым идиоматическим способом?

Я мог бы написать небольшую рекурсивную функцию для репликации цикла. Но это похоже на то, что засоряется, чтобы вывесить небольшую подколесу, которая не имеет никакого значения сама по себе как автономная, названная функция.

Я хочу сделать это со списком функций. У меня есть пара идей, но я еще не там. Кто-нибудь получил это в мгновение ока?

Две туманные идеи, которые у меня есть: 1. Я мог бы сделать еще два списка, отрубив один (и два) элемента и добавив нулевой элемент (ы). И объедините эти списки. 2. Мне интересно, может ли функция списка, например map, использовать в качестве аргументов термины в списке. 3. Как общий вопрос, я задаюсь вопросом, может ли это быть случай, когда опытный человек скажет, что эта проблема кричит о изменчивых ценностях (и если это так ослабит мой энтузиазм, чтобы попасть на функциональную лодку).

Чтобы дать больше интуиции для кода: полная функция, из которой это выписано, является численным приближением для кумулятивного нормального распределения. Я не искал математику за этим. «xa» - это абсолютное значение аргумента главной функции «x», которое является числом стандартных отклонений от нуля. Не работая через доказательство, я не думаю, что есть что сказать больше, чем: это просто формула. (О, и, возможно, мне нужно изменить имена переменных - xa и bm и т. Д. - довольно убогие. Я сделал предложения в качестве комментариев.)

+1

Чистых запросов кода письма являются вне темы на переполнение стека - мы ожидаем, что вопросы здесь, чтобы относиться к * * специфические проблемы программирования - но мы с радостью помогут вам написать его сами! Сообщите нам [что вы пробовали] (http://whathaveyoutried.com), и где вы застряли. Это также поможет нам лучше ответить на ваш вопрос. – CoderDennis

+0

Хорошо, спасибо. Я добавлю немного. Это тяжело. Я все еще пытаюсь настроить его достаточно разумно, чтобы создать его. – RomnieEE

+0

Возможно, также включают в себя те 'T' и' xa', и описание того, что вещь должна делать. – CoderDennis

ответ

1

Это просто стандартная рекурсия. Вы делаете свое условие выхода и условие возврата.

let rec calc i prevPrev prev total = 
    if i = 0 then // exit condition; do your final calc 
    exp(-xa * xa) * (total - prevPrev)/4. 
    else // recur condition, call again 
    let newPrevPrev = prev 
    let newPrev = total 
    let newTotal = (T * newPrev - newPrevPrev + a i) 
    calc (i-1) newPrevPrev newPrev newTotal 

calc 24 initPrevPrev initPrev initTotal 

или короче ...

let rec calc i prevPrev prev total = 
    if i = 0 then 
    exp(-xa * xa) * (total - prevPrev)/4. 
    else 
    calc (i-1) prev total (T * total - prev + a i) 
+0

О да, это хорошо. Я действительно испортил это. Благодарю. – RomnieEE

0

Вот моя попытка вытащить петлю в качестве рекурсивной функции. Я не волнуюсь о домашнем хозяйстве, чтобы иметь это отдельно, но я думаю, что синтаксис является опрятным. Помимо ошибки в последней строке, то есть, где звездочка в (c * a.Tail.Head) получает красную squiggly для списка с плавающей точкой, которая не соответствует типу float (но я думал, что .Head обязательно возвратил float not list):

let rec RecurseIt (a: float list) c = 
    match a with 
    | []->    0.0 
    | head::[]->  a.Head 
    | head::tail::[]-> a.Head + (c * a.Tail) + (RecurseIt a.Tail c)        
    | head::tail->  a.Head + (c * a.Tail.Head) - a.Tail.Tail.Head + (RecurseIt a.Tail c) 

Теперь я попробую список функций. Похоже, мне придется перебирать элемент, а не находить одноразовый подход.

Также я отмечаю в этой рекурсивной функции, что все мои рекурсивные вызовы находятся в хвостовой позиции, я думаю - за исключением последней, которая выйдет на одну строку раньше. Интересно, создает ли это риск переполнения стека (т. Е. Не позволяет компилятору рассматривать рекурсию как цикл (если это правильное описание) или если я все еще в безопасности, потому что алгоритм будет работать как цикл плюс только один уровень рекурсия).

EDIT: Вот как я попытался вернуть список вместо суммы списка (чтобы я мог использовать третий-последний элемент, а также суммировать элементы), но я ушел с этим синтаксисом и все еще взломать у него:

let rec RecurseIt (a: float list) c = 
    match a with 
    | []->    [] 
    | head::[]->  [a.Head] 
    | head::tail::[]-> [a.Head + (c * a.Tail)] :: (RecurseIt a.Tail c)        
    | head::tail->  [a.Head + (c * a.Tail.Head) - a.Tail.Tail.Head] :: (RecurseIt a.Tail c) 
+0

О, одна проблема с этим подходом заключается в том, что алгоритм использует сумму из 25 терминов (с использованием 25-элементного массива), возвращаемых этой функцией, но алгоритм также использует 23-й терм этой суммы. Поэтому я действительно должен вернуть список элементов, которые суммируются. Что я начал делать, но имел проблемы с синтаксисом. Я должен уметь это получить. – RomnieEE

0

Вот моя попытка в функции списка. Я думаю, что проблема была сложнее, чем из-за смущения. У меня просто была какая-то глупость в List.iteri. Надеюсь, это ближе к пониманию. Я надеялся, что какой-то Список. функция будет аккуратной. Не обошлось. Думаю, для петли не так уж идиоматично. :

for i in 0 .. a.Length - 1 do 
    b:: 
     a.Item(i) + 
      if i > 0 then 
       T * b.Item(i-1) - 
        if i > 1 then 
         b.Item(i-2) 
        else 
         0 
      else 
       0 
Смежные вопросы