Seq和PSeq ToDictionary之间的F#Func类型推断差异 [英] F# Func type inference difference between Seq and PSeq ToDictionary

查看:86
本文介绍了Seq和PSeq ToDictionary之间的F#Func类型推断差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出一个简单的元组序列,并使用F#PowerPack的PSeq生成一个并行的元组:

Given a trivial sequence of tuples, and a parallel one using F# PowerPack's PSeq:

let a = Seq.singleton (1,"a")  --> val a: seq<int * string>
let b = a |> PSeq.map id       --> val b: pseq<int * string>

现在,我想根据他们创建一个.Net BCL字典:

Now I'd like to create a .Net BCL dictionary from them:

let bd = b.ToDictionary(fst, snd, HashIdentity.Structural)
let ad = a.ToDictionary(fst, snd, HashIdentity.Structural)
let ad2 = a.ToDictionary(fst, snd)
let ad3 = a.ToDictionary((fun (x,y) -> x), (fun (x,y) -> y), HashIdentity.Structural)

虽然let bd可以工作,但let ad不能编译,因为它无法推断类型并不能正确转换为BCL的Func.有趣的是,如果我在let ad2中省略了第三个参数,或者在let ad3中手动内联写出了fstsnd,它就可以正常工作.

While let bd works, let ad does not compile as it fails to infer types and convert to BCL's Func correctly. Interestingly it works just fine if I omit the third parameter, as in let ad2, or if I write out fst and snd manually inline as in let ad3.

该表达式的类型应为Func<(int * string),'a>,但此处的类型为'b *'c->'b

This expression was expected to have type Func<(int * string),'a> but here has type 'b * 'c -> 'b

  • 为什么let ad无法编译,而所有替代方法都可以正常工作?
  • 是否可以在不提供内联函数或类型注释的情况下进行let ad编译?
    • Why does let ad not compile, while all the alternatives work fine?
    • Is there a way to make let ad compile, without providing inline functions or type annotations?
    • PS:我需要HashIdentity.Structural,因为在实际代码中,键不是整数而是元组或记录

      PS: I need HashIdentity.Structural because in the real code the keys are not integers but tuples or records

      更新:我现在已经定义了let dictionary (s : ('a * 'b) seq) = s.ToDictionary((fun (x,y)->x), (fun (x,y)->y), HashIdentity.Structural),因此我可以只编写let ad = a |> dictionary,但是我仍然对为什么它不能使用fstsnd函数进行编译仍然很感兴趣.

      Update: I've now defined let dictionary (s : ('a * 'b) seq) = s.ToDictionary((fun (x,y)->x), (fun (x,y)->y), HashIdentity.Structural) so I can just write let ad = a |> dictionary, but I'm still interested in why it won't compile with the fst and snd functions.

      推荐答案

      我相信这并不是一个错误,而只是F#类型推断算法的一个非常丑陋的极端情况,其中涉及重载和类型定向转换.奇怪的是,编译器会正确地推断ad2绑定的类型,因为ToDictionary的第二个重载有两个参数,这会在推理过程中导致额外的重载解析步骤.另一方面,只有一个带有三个参数的重载,因此在尝试推断ad的类型时不使用重载解决步骤.

      I believe that this is not exactly a bug, but merely a very ugly corner case of F#'s type inference algorithm where overloads and type directed conversions are involved. Oddly, the compiler infers the ad2 binding's type correctly because there's a second overload of ToDictionary that has two arguments, which causes an additional overload resolution step during inference. On the other hand, there is only a single overload with three arguments, so the overload resolution step isn't used when trying to infer ad's type.

      正如我提到的,另一个难题是从F#函数到.NET委托类型的类型定向转换(这是在期望Func<_,_>的地方传递F#函数的方式).基本上,如果您使用显式lambda或存在多个重载,则将考虑此转换,但是如果只有单个重载而没有显式lambda,则不考虑该转换.这意味着以下内容也将起作用:

      As I mentioned, the other piece of the puzzle is the type directed conversion from an F# function to a .NET delegate type (this is how you can pass an F# function where a Func<_,_> is expected). Basically, if you use an explicit lambda or if there are multiple overloads, then this conversion is considered, but if there is only a single overload and no explicit lambda then the conversion isn't considered. This means that the following will also work:

      let ad3 = a.ToDictionary(System.Func<_,_>(fst), 
                               System.Func<_,_>(snd), HashIdentity.Structural)
      

      因为现在不需要执行类型定向转换.

      because now there's no need to perform a type directed conversion.

      这个结果肯定是违反直觉的,所以我希望有某种方法可以调整类型推断算法,以更好地处理这些极端情况.不幸的是,与.NET类型系统的某些方面(例如,命名委托类型,子类型,重载等)进行互操作使推理比原本要困难得多,并且可能由于某些原因,该算法无法轻松实现.进行了修改以处理这种情况.

      This result is certainly counterintuitive, so I'd hope that there is some way to tweak the type inference algorithm to better handle these corner cases. Unfortunately, interoperating with certain aspects of the .NET type system (such as named delegate types, subtyping, overloading, etc.) makes inference much harder than it might otherwise be, and there may be some reason that the algorithm can't easily be modified to handle this case.

      这篇关于Seq和PSeq ToDictionary之间的F#Func类型推断差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆