Compiler errors 无法确定F#函数中的对象类型

Compiler errors 无法确定F#函数中的对象类型,compiler-errors,f#,functional-programming,Compiler Errors,F#,Functional Programming,我在F#中有下面的函数,不幸的是,在折叠开始时的Seq.filter中,w2.Text(在比较中)未标识为Word类型。我不知道如何在这种情况下帮助编译器。编译器似乎在其他方面都很好。这是我第一次碰到这个 let CreateWordRelationDB () = let db = new AnnotatorModel() printfn "%s" "Entered Function and created db v7" let tweets = db.Tweets

我在F#中有下面的函数,不幸的是,在折叠开始时的Seq.filter中,w2.Text(在比较中)未标识为Word类型。我不知道如何在这种情况下帮助编译器。编译器似乎在其他方面都很好。这是我第一次碰到这个

let CreateWordRelationDB () =
    let db = new AnnotatorModel()
    printfn "%s" "Entered Function and created db v7"
    let tweets = db.Tweets
                |> Seq.cast<Tweet>
                |> Seq.map(fun t -> t.Text)
    let words = db.Words |> Seq.cast<Word> 
    words 
    |> Seq.fold(fun acc w1 ->  
                        let filtacc = acc 
                                      |> Seq.filter(fun w2 -> 
                                                        if(w1.Text = w2.Text) then false else true)
                        filtacc 
                        |> Seq.map(fun w2 -> CreateWordRelation w1 w2 tweets)
                        |> Seq.iter(fun r -> db.WordRelations.Add(r) |> ignore)
                        db.SaveChanges() |> ignore
                        filtacc
                    ) words
let CreateWordRelationDB()=
设db=newannotatormodel()
printfn“%s”输入了函数并创建了db v7
让tweets=db.tweets
|>序号
|>序列图(趣味t->t.Text)
让words=db.words |>Seq.cast
话
|>顺序折叠(根据w1->
设filtacc=acc
|>序列过滤器(乐趣w2->
如果为(w1.Text=w2.Text),则为false,否则为true)
filtacc
|>Seq.map(趣味w2->CreateWordRelation w1 w2推文)
|>Seq.iter(fun r->db.WordRelations.Add(r)|>ignore)
db.SaveChanges()|>忽略
filtacc
)言语

您可以添加类型批注:

|> Seq.filter(fun (w2: Word) -> if(w1.Text = w2.Text) then false else true)

可以说,有一种比使用类型注释更优雅的方法

这里的问题是,非F#类型(本质上是Word)的类型推断不如F#record/DU类型强大。如果代码中的相应值出现在使用它的点之前,编译器只能推断这些值的类型(因此它的推断不是那么多,而是更多的“类型跟踪”)

您正以这种方式使用
fold
source>Seq.fold文件夹状态

因此,仍需确定其类型的
状态发生在使用该状态的
文件夹
函数之后。但是,您可以使用不太为人所知的
| |>
操作符将其移动到该点之前

此运算符定义为
let inline(| |>)(a,b)f=f a b
,并允许您将两个单独的参数“插入”函数:
(状态,源)| |>Seq.fold文件夹

这样,
状态
出现在
文件夹
中需要了解其类型之前,编译器可以“记住”该类型并在相关位置使用它

这样,您的函数调用将如下所示

(words, words) // The first is the state, the second the source
||> Seq.fold (fun acc w1 -> ... // long folder function)
folder
函数插入到
Seq.fold
之后没有进一步的参数


(这一切都归功于罗斯·麦金莱,我从他那里学到了这一点。)

哇,我是个傻瓜,我完全忘了我可以在函数中的那个点放置paren…我倾向于将注释放在最靠近需要它的点的位置,例如
(w2:Word)。Text
。我不确定这是否被视为良好实践或惯用做法,但这确实意味着,如果注释的原因被删除,那么注释可能会被删除,而不是作为杂乱无章的东西留在后面。可以简化一下:|>Seq.filter(fun(w2:Word)->w1.Text w2.Text)这通常只发生在两种类型共享表达式中使用的字段的情况下,或者使用的是类而不是记录-由于类中的某些特性,例如方法重载,编译器无法推断此类类型。非常简洁。这就是为什么我有时会阅读F#源代码来查找类似的内容。