smlnj как перебрать значение
Я новичок в функциональном программировании, но у меня есть опыт в императивном программировании, особенно на Java. я хотел бы спросить, как значение повторяется в smlnj, я знаю, что на Java вы можете использовать varName += anyNumber или varName = varName + 1. на smlnj я не знаю, как это сделать, и мое значение var не повторяется здесь образец моего кода. заранее спасибо.
fun number_in_month (dates : (int*int*int) list , month : int) =
let
val total = 0;
in
let
fun check(date : (int*int*int) list , m : int) =
if #2(hd(date)) = m
then total + 1 (* this is the problem in the code i don't know
how to iterate this like "varName += 1" in java *)
else check(tl(date),m)
in
check(dates,month)
end
end
эта программа проверит, существуют ли введенные даты (в списке) в указанный месяц, и выведет, сколько дат существует в этом месяце.
например: number_in_month ([(год, месяц, день)],monthEntered) number_in_month([(2017,2,1),(2015,2,3),(2012,1,2)],2) выходные данные должны быть 2 потому что первый и второй элемент в списке равен monthEntered.
проблема в моем коде в том, что он просто выводит 1, даже если все введенные мной даты равны месяцу, который я ввожу. я просто хочу знать, почему он просто выводит 1 и как мне это исправить. Заранее спасибо
2 ответа
Эквивалентом обновления изменяемой переменной с помощью итерации является повторное связывание неизменяемого параметра функции с помощью рекурсии. Поэтому вместо "foo() { while (p) { x++; }}" в псевдокоде вы делаете "foo(p,x) { if (p) { foo(p,x+1); } }". Или в SML,
type date = {year : int, month : int, day : int}
fun countMonth month (dates : date list) =
let fun countMonth' [] count = count
| countMonth' (d::ds) count =
if #month d = month
then countMonth' ds (count+1)
else countMonth' ds count
in countMonth' dates 0 end
Но вот как я написал бы функцию, которая фильтрует число дат в списке, которые принадлежат данному месяцу, используя функцию более высокого порядка:
type date = {year : int, month : int, day : int}
fun filterMonth month (dates : date list) =
List.filter (fn d => #month d = month) dates
fun countMonth month dates =
List.length (filterMonth month dates)
Как правило, в языке, который не поддерживает циклы (для или пока), вашим следующим выбором всегда должна быть рекурсия. В этом конкретном случае рекурсивные вызовы этой функции должны быть тем, как вы «увеличиваете» результат.
Просто подумайте о проблеме в обратном порядке: «Она должна вернуть 1 в случае совпадения и 0 в противном случае» — это будет означать, что вызов функции внутри себя потенциально вернет 1 дважды, вызов ее 3 раза вернет 1 три раз и т. д. Теперь нужно только сложить все успешные случаи, когда рекурсивный вызов функции фактически возвращает 1. И не беспокойтесь о бесконечной рекурсии, поскольку в противном случае она вернет 0 и приведет к краху дерева рекурсии.
fun number_in_month(dates: (int * int * int) list, month: int) =
if null dates
then 0
else
if #2 (hd dates) = month
then 1 + number_in_month(tl dates, month) (* <--this is where the magic happens *)
else number_in_month(tl dates, month)