Обратите внимание, что все функции SML принимают один вход и возвращают один выход. Вместо этого подумайте о возврате кортежа, содержащего новый список и флаг, указывающий, были ли удалены какие-либо элементы. Одна возможность состоит в том, чтобы использовать пару функций из стандартной базы, чтобы проверить, находится ли elem
в myList
, и создать кортеж, состоящий из этого и результатов из filter
, показанных в вопросе. Тест может выглядеть так:
Option.isSome (List.find (fn x => x = elem) myList)
Есть более краткие способы написать это, но это показывает идею. Обратите внимание, что он возвращает bool
вместо int
; это более точно, поэтому я не буду преобразовывать в целые числа, запрошенные в вопросе.
Недостаток вышесказанного заключается в том, что он требует обхода списка дважды. Чтобы избежать этого, рассмотрим тип , который должна возвращать функция: кортеж списка без elem
и флаг, показывающий, были ли удалены какие-либо elem
. Затем мы можем написать функцию, которая принимает новое значение и (действительный) кортеж и возвращает действительный кортеж. Одна возможность:
fun update(x, (acc, flag)) = if x = elem then (acc, true) else (x :: acc, flag)
Затем мы можем применить update
к каждому элементу myList
один за другим. Поскольку мы хотим, чтобы порядок в списке оставался неизменным, кроме удаленных элементов, мы должны пройти через myList
справа налево, накапливая результаты в первоначально пустой список. Функция foldr
сделает это напрямую:
foldr update ([], false) myList
Однако в функции высшего порядка foldr
скрыто много логики.
Чтобы использовать это как учебное упражнение, я бы предложил использовать эту задачу для реализации функции несколькими способами:
- как рекурсивная функция
- как хвостовая рекурсивная функция
- с использованием функций высшего порядка
foldl
и foldr
Понимание различий между этими версиями поможет понять, как работает SML. Для каждой версии позволяют типам ориентироваться.