Функция в вашем вопросе будет работать с некоторыми изменениями:
let rec doubleListElements list =
match list with
| [] -> []
| head::tail -> head*2::doubleListElements tail
Первая важная вещь, которую нужно иметь в виду, это «что я хочу дать и получить от этой функции». В вашем случае ваш ввод int list
, а желаемый вывод int list
. Это означает, что где бы ваша функция не возвращала значение, оно должно быть int list
. Ваша функция имеет два места, где возвращается значение:
| [] -> [] // return empty list
| head::tail ->
head*2::doubleListElements tail // return a list (but recurse)
В вашей исходной функции ваши возвращаемые значения всегда 0
, что, конечно, не соответствует типу возврата int list
.
|[]-> 0 // return value
|head::tail ->
let doubledList = [head*2::doubleListElements tail]
0 // return value
В этом выражении создается doubledList
, но это значение по существу отбрасывается, поскольку оно не используется и не является возвращаемым значением . Возвращаемое значение является окончательным значением в выражении: 0
. Я думаю, что это очень распространенная ошибка, когда люди изучают функциональные языки, которые основаны на выражениях и основаны на императивных основанных на выражениях языках.
В этом конкретном выражении имеет значение только конечное значение. В языке, основанном на выражениях, вы могли видоизменить некоторое состояние программы перед возвратом значения (что также вполне возможно в F #, но обычно избегают изменчивости).
let foo x =
let y = x + x // the value of this expression is discarded: y is unused
x * x // the value of this expression is returned
Единственное другое необходимое изменение - не переносить возвращаемый список в другой список в каждой рекурсии. head*2::doubleListElements tail
это просто список. [head*2::doubleListElements tail]
- это тот же список внутри другого списка , потому что он заключен в литералы списка в квадратных скобках. После этого изменения это работает:
val printList : int list = [10; 20; 30; 40; 50; 60]