Удаление стоп-слов в 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"]
Другие вопросы по тегам