我正在尝试编写一个代码来删除字符串列表中的“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
答案 0 :(得分:4)
F#中的匹配表达式非常强大,但语法首先令人困惑
您需要像这样匹配列表:
let rec stopword a =
match a with
|"the"::t |"this"::t -> stopword t
|h::t ->h::(stopword t)
|[] -> []
答案 1 :(得分:2)
实际错误是由于函数需要一个元组参数。您必须使用以下命令调用该函数:
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"]
答案 2 :(得分:2)
在这种情况下,其他人已经提到过模式匹配的力量。实际上,您通常会有一组要删除的停用词。 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 module中使用尾递归的高阶函数是个好主意:
let removeStopwords (stopwords: Set<string>) xs =
xs |> List.filter (stopwords.Contains >> not)