Удаление стоп-слов в F#
Я пытаюсь написать код для удаления стоп-слов, таких как "the", "this" в списке строк и т. Д.
Я написал этот код:
let rec public stopword (a : string list, b :string list) =
match [a.Head] with
|["the"]|["this"] -> stopword (a.Tail, b)
|[] -> b
|_ -> stopword (a.Tail, b@[a.Head])
Я запустил это в интерактиве:
stopword (["this";"is";"the"], []);;
Я получил эту ошибку:
This expression was expected to have type string list but here has type 'a * 'b
3 ответа
Выражения соответствия в F# очень мощные, хотя синтаксис поначалу сбивает с толку
Вам нужно сопоставить список следующим образом:
let rec stopword a =
match a with
|"the"::t |"this"::t -> stopword t
|h::t ->h::(stopword t)
|[] -> []
Другие упомянули силу сопоставления с образцом в этом случае. На практике у вас обычно есть набор стоп-слов, которые вы хотите удалить. И when
Страж позволяет нам сгенерировать совпадение вполне естественно:
let rec removeStopwords (stopwords: Set<string>) = function
| x::xs when Set.contains x stopwords -> removeStopwords stopwords xs
| x::xs -> x::(removeStopwords stopwords xs)
| [] -> []
Проблема с этой функцией и ответом @John заключается в том, что они не являются хвостово-рекурсивными. Они заканчиваются в длинном списке, состоящем из нескольких стоп-слов. Хорошей идеей является использование функций высокого порядка в модуле List с хвостовой рекурсией:
let removeStopwords (stopwords: Set<string>) xs =
xs |> List.filter (stopwords.Contains >> not)
Фактическая ошибка связана с тем, что функция ожидает аргумент кортежа. Вы должны были бы вызвать функцию с:
let result = stopword (["this";"is";"the"], [])
Изменить: так как исходный вопрос был изменен, приведенный выше ответ больше не действителен; логическая ошибка в реальной функции заключается в том, что вы получаете один элемент списка, из которого берется хвост, в результате чего получается пустой список. При следующем рекурсивном вызове функция захлебывается при попытке получить заголовок этого пустого списка
Сама по себе функция реализована некорректно и намного сложнее, чем необходимо.
let isNoStopword (word:string) =
match word with
| "the"|"this" -> false
| _ -> true
let removeStopword (a : string list) =
a |> List.filter(isNoStopword)
let test = removeStopword ["this";"is";"the"]