Ваша sumList
функция - хорошее начало. Он уже повторяется (рекурсивно) по всему списку, поэтому вам не нужно оборачивать его в дополнительный Array.map
. Вам просто нужно расширить sumList
, чтобы оно добавляло число только тогда, когда оно соответствует указанному условию.
Вот решение упрощенной задачи - добавьте все числа, которые делятся на 3:
open System
let rec sumList xs =
match xs with
| [] -> 0 // If the list is empty, the sum is zero
| y::ys when y % 3 = 0 ->
// If the list starts with y that is divisible by 3, then we add 'y' to the
// sum that we get by recursively processing the rest of the list
y + sumList ys
| y::ys ->
// This will only execute when y is not divisible by 3, so we just
// recursively process the rest of the list and return
/// that (without adding current value)
sumList ys
// For testing, let's sum all numbers divisble by 3 between 1 and 10.
let sum = sumList [ 1 .. 10 ]
Это основной способ написания функции с использованием явной рекурсии. На практике, решение jpalmer - это то же самое, что и я, но полезно написать несколько рекурсивных функций самостоятельно, если вы изучаете F #.
Параметр аккумулятора , упомянутый sashang , является более продвинутым способом написания этого. Это необходимо сделать, если вы хотите запустить функцию на больших входах (что, вероятно, имеет место в случае проблемы Эйлера). При использовании параметра аккумулятора функция может быть написана с использованием хвостовой рекурсии , поэтому она позволяет избежать переполнения стека даже при обработке длинных списков.
Идея версии, основанной на аккумуляторе, состоит в том, что функция принимает дополнительный параметр, который представляет собой сумму, вычисленную до настоящего времени.
let rec sumList xs sumSoFar = ...
При первоначальном вызове вы пишете sumList [ ... ] 0
. Рекурсивные вызовы не будут вызывать y + sumList xs
, но вместо этого добавят y
к аккумулятору и затем сделают рекурсивный вызов sumList xs (y + sumSoFar)
. Таким образом, компилятор F # может выполнять оптимизацию хвостового вызова и переводит код в цикл (аналогично версии C ++).