我正试图写一段代码来删除字符串列表中的"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
F#中的Match表达式非常强大,尽管最初中的语法很混乱
你需要这样匹配列表:
let rec stopword a =
match a with
|"the"::t |"this"::t -> stopword t
|h::t ->h::(stopword t)
|[] -> []
实际错误是由于函数需要一个元组参数。你必须用调用函数
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"]
其他人已经提到了模式匹配在这种情况下的威力。在实践中,您通常有一组要删除的停止语。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的答案的问题在于它们不是尾递归的。它们在一个由几个停止语组成的长列表中用完了。在列表模块中使用尾部递归的高阶函数是一个好主意:
let removeStopwords (stopwords: Set<string>) xs =
xs |> List.filter (stopwords.Contains >> not)