委托/函数转换和误导性编译器错误消息 [英] Delegate/Func conversion and misleading compiler error message

查看:12
本文介绍了委托/函数转换和误导性编译器错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为 F# 函数和 System.Func 之间的转换必须手动完成,但似乎存在编译器(有时)为您完成的情况.当它出错时,错误信息不准确:

I thought that conversions between F# functions and System.Func had to be done manually, but there appears to be a case where the compiler (sometimes) does it for you. And when it goes wrong the error message isn't accurate:

module Foo =
    let dict = new System.Collections.Generic.Dictionary<string, System.Func<obj,obj>>()

    let f (x:obj) = x

    do
        // Question 1: why does this compile without explicit type conversion?
        dict.["foo"] <- fun (x:obj) -> x 
        // Question 2: given that the above line compiles, why does this fail?
        dict.["bar"] <- f 

最后一行编译失败,报错为:

The last line fails to compile, and the error is:

This expression was expected to have type
    System.Func<obj,obj>    
but here has type
    'a -> obj

显然函数 f 没有 'a > 的签名.对象.如果 F# 3.1 编译器对第一个字典赋值感到满意,那么为什么第二个不满意?

Clearly the function f doesn't have a signature of 'a > obj. If the F# 3.1 compiler is happy with the first dictionary assignment, then why not the second?

推荐答案

应该解释这一点的规范部分是 8.13.7 成员调用时的类型定向转换.简而言之,在调用成员时,将应用从 F# 函数到委托的自动转换.不幸的是,规范有点不清楚;从措辞上看,这种转换可能适用于任何函数表达式,但实际上它似乎只适用于匿名函数表达式.

The part of the spec that should explain this is 8.13.7 Type Directed Conversions at Member Invocations. In short, when invoking a member, an automatic conversion from an F# function to a delegate will be applied. Unfortunately, the spec is a bit unclear; from the wording it seems that this conversion might apply to any function expression, but in practice it only appears to apply to anonymous function expressions.

规范也有点过时了;在 F# 3.0 中,类型定向转换还可以转换为 System.Linq.Expressions.Expression.

The spec is also a bit out of date; in F# 3.0 type directed conversions also enable a conversion to a System.Linq.Expressions.Expression<SomeDelegateType>.

编辑

在查看过去与 F# 团队的一些通信时,我想我已经找到了如何将转换应用于非语法函数表达式.为了完整起见,我将其包括在此处,但它有点奇怪,因此对于大多数用途,您可能应该考虑规则是只有语法函数才会应用类型定向转换.

In looking at some past correspondence with the F# team, I think I've tracked down how a conversion could get applied to a non-syntactic function expression. I'll include it here for completeness, but it's a bit of a strange corner case, so for most purposes you should probably consider the rule to be that only syntactic functions will have the type directed conversion applied.

例外是重载解析会导致转换函数类型的任意表达式;这部分由 14.4 方法应用部分解释分辨率,虽然它很密集,但仍然不完全清楚.基本上,参数表达式仅在有多个重载时详细说明;当只有一个候选方法时,参数类型针对未详细说明的参数进行断言(注意:这并不明显,这实际上与转换是否适用有关,但从经验上来说确实很重要).这是一个演示此异常的示例:

The exception is that overload resolution can result in converting an arbitrary expression of function type; this is partly explained by section 14.4 Method Application Resolution, although it's pretty dense and still not entirely clear. Basically, the argument expressions are only elaborated when there are multiple overloads; when there's just a single candidate method, the argument types are asserted against the unelaborated arguments (note: it's not obvious that this should actually matter in terms of whether the conversion is applicable, but it does matter empirically). Here's an example demonstrating this exception:

type T =
    static member M(i:int) = "first overload"
    static member M(f:System.Func<int,int>) = "second overload"

let f i = i + 1

T.M f |> printfn "%s" 

这篇关于委托/函数转换和误导性编译器错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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