2

在重构一些 F# 代码时,我遇到了一个我无法理解或解决的问题。我有一个类 Problem,有 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# 友好的构造函数中的 mutator 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 个参数即可。

4

1 回答 1

2

阅读规范(8.13.6)给出:

第一个类型导向的转换将匿名函数表达式和其他函数值参数转换为委托类型。鉴于:

委托类型 D 的形式参数

· 已知类型的实际参数 fargty1 -> ... -> tyn -> rty

· 委托类型 D 的 Invoke 方法的精确 n 个参数

然后:

· 参数被解释为好像它是这样写的: new D(fun arg1 ... argn -> farg arg1 ... argn)

当这些条件适用时,Func代表被转换为柯里化形式,因此存在歧义。

于 2012-05-29T04:00:11.593 回答