2013-11-15 5 views
1

Я хотел бы получить более удобное функциональное программирование, и первая образовательная задача, которую я установил, - это преобразование программы, которая вычисляет звуковые частоты от C# до F #. Мяг оригинального приложения представляет собой большой цикл «для», который выбирает подмножество значений в большом массиве; какие значения взяты, зависит от последнего принятого значения и ранжированного списка значений, наблюдаемых с тех пор. Существует несколько переменных, которые сохраняются между итерациями для отслеживания прогресса в направлении определения следующего значения.Какой самый «функциональный» способ выбрать подмножество из этого массива?

Моя первая попытка сделать этот цикл более «функциональным» связана с хвостовой рекурсивной функцией, аргументы которой включают в себя массив, набор результатов до сих пор, ранжированный список недавно полученных значений и несколько других элементов, которые необходимо сохранить между казнями. Это кажется неуклюжим, и я не чувствую, что получил что-либо, превратив все, что раньше было переменной в параметр этой рекурсивной функции.

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

Вот попытка перегонка кода, с некоторыми «пусть» заявления и действительные компоненты состояния удалены («Темп» промежуточный результат массив, который должен быть обработан):

let fif (_,_,_,_,fif) = fif 

temp 
|> Array.fold (fun (a, b, c, tentativeNextVals, acc) curVal -> 
    if (hasProperty curVal c) then 
     // do not consider current value 
     (a, b, c, Seq.empty, acc) 
    else 
     if (hasOtherProperty curVal b) then 
      // add current value to tentative list 
      (a, b, c, tentativeNextVals.Concat [curVal], acc) 
     else 
      // accept a new value 
      let newAcceptedVal = chooseNextVal (tentativeNextVals.Concat [curVal]) 

      (newC, newB, newC, Seq.empty, acc.Concat [newAcceptedVal]) 

) (0,0,0,Seq.empty,Seq.empty) 
|> fif 

ответ

2

Что-то вроде это используя сгиб?

let filter list = 
    List.fold (fun statevar element -> if condition statevar then statevar else element) initialvalue list 
0

Попробуйте использовать Seq.skip и Seq.take:

let subset (min, max) seq = 
    seq 
    |> Seq.skip (min) 
    |> Seq.take (max - min) 

Эта функция принимает массивы, но возвращает последовательность, так что вы можете преобразовать его обратно с помощью Array.ofSeq.

PS: Если ваша цель состоит в том, чтобы ваша программа функционировала, самым важным правилом является следующее: избегайте изменчивости настолько, насколько сможете. Это означает, что вы, вероятно, не должны использовать массивы; которые являются неизменными. Если вы используете массив для быстрого получения произвольного доступа, пойдите для него; просто не забудьте никогда не устанавливать индексы.

+0

Этот вопрос не о взятии блока из массива –

Смежные вопросы