在重构一些 F# 代码时,我遇到了一个我无法理解或解决的问题。我有一个类问题,有 2 个构造函数,一个默认用于 F# 消耗,一个用于 C# 方便,它接受 Funcs 并将它们“转换”为 F# 函数:
open System
type Problem<'d, 's> (data: 'd, generate: 'd -> Random -> 's, mutate: 'd -> Random -> 's -> 's, evaluate: 's -> float) =
member this.Data = data
member this.Generate = generate this.Data
member this.Mutate = mutate this.Data
member this.Evaluate = evaluate
new (data: 'd, generator: Func<'d, Random, 's> , mutator: Func<'d, 's, Random, 's> , evaluator: Func<'s, float>) =
let generate (data: 'd) rng = generator.Invoke(data, rng)
let mutate (data: 'd) (rng: Random) (solution: 's) = mutator.Invoke(data, solution, rng)
let evaluate (solution: 's) = evaluator.Invoke(solution)
Problem(data, generate, mutate, evaluate)
据我所知,它的构建和工作符合预期。
出于某种强制性,我注意到 C# 友好的构造函数中的变元 Func 对于参数有不同的顺序,因此我继续以这种方式重写它(第一部分不变):
new (data: 'd, generator: Func<'d, Random, 's> , mutator: Func<'d, Random, 's, 's> , evaluator: Func<'s, float>) =
let generate = fun (data: 'd) rng -> generator.Invoke(data, rng)
let mutate = fun (data: 'd) (rng: Random) (solution: 's) -> mutator.Invoke(data, rng, solution)
let evaluate = fun (solution: 's) -> evaluator.Invoke(solution)
Problem(data, generate, mutate, evaluate)
虽然这 3 个函数似乎具有正确的签名,但最后一行失败并显示红色波浪线,告诉我“无法根据此程序之前的类型信息确定方法‘Problem`2’的唯一重载点。可用的重载如下所示(或在“错误列表”窗口中)。可能需要类型注释。
谁能帮我看看我错过了什么?我尝试对最后一行中的 4 个参数进行类型注释,但无济于事 - 而且我不知道如何解决这个问题。同样让我感到奇怪的是,以前的版本只需在 Func 中反转 2 个参数就可以工作。
最佳答案
阅读规范(8.13.6)给出:
The first type-directed conversion converts anonymous function expressions and other function-valued arguments to delegate types. Given:
A formal parameter of delegate type D
· An actual argument farg of known type
ty1 -> ... -> tyn -> rty
· Precisely n arguments to the Invoke method of delegate type D
Then:
· The parameter is interpreted as if it were written:
new D(fun arg1 ... argn -> farg arg1 ... argn)
当这些条件适用时,Func
委托(delegate)将转换为柯里化(Currying)形式,因此存在歧义。
关于更改 Func 参数顺序后,F# 构造函数无法构建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10792054/