gpt4 book ai didi

c# - 如何将 `where T : U` 泛型类型参数约束从 C# 转换为 F#?

转载 作者:可可西里 更新时间:2023-11-01 03:10:29 24 4
gpt4 key购买 nike

F# 的类型推断规则给我带来了一些麻烦。我正在编写一个简单的计算构建器,但无法正确设置泛型变量约束。


我想要的代码在 C# 中如下所示:

class FinallyBuilder<TZ>
{
readonly Action<TZ> finallyAction;

public FinallyBuilder(Action<TZ> finallyAction)
{
this.finallyAction = finallyAction;
}

public TB Bind<TA, TB>(TA x, Func<TA, TB> cont) where TA : TZ
{ // ^^^^^^^^^^^^^
try // this is what gives me a headache
{ // in the F# version
return cont(x);
}
finally
{
finallyAction(x);
}
}
}

到目前为止,我为 F# 版本 提出的最好的(但非编译代码)是:

type FinallyBuilder<′z> (finallyAction : ′z -> unit) =

member this.Bind (x : ′a) (cont : ′a -> ′b) =
try cont x
finally finallyAction (x :> ′z) // cast illegal due to missing constraint

// Note: ' changed to ′ to avoid bad syntax highlighting here on SO.

不幸的是,我不知道如何翻译 where TA : TZ Bind 上的类型约束方法。我认为它应该类似于 ′a when ′a :> ′z ,但 F# 编译器在任何地方都不喜欢这样,我总是以一些泛型类型变量约束到另一个结束。

有人可以告诉我正确的 F# 代码吗?


背景:我的目标是能够像这样编写 F# 自定义工作流:

let cleanup = new FinallyBuilder (fun x -> ...)

cleanup {
let! x = ... // x and y will be passed to the above lambda function at
let! y = ... // the end of this block; x and y can have different types!
}

最佳答案

我认为不可能在 F# 中编写这样的约束(尽管我不确定为什么)。不管怎样,从句法上讲,你会想写这样的东西(正如 Brian 建议的那样):

type FinallyBuilder<'T> (finallyAction : 'T -> unit) = 
member this.Bind<'A, 'B when 'A :> 'T>(x : 'A) (cont : 'A -> 'B) = //'
try cont x
finally finallyAction (x :> 'T)

不幸的是,这会产生以下错误:

error FS0698: Invalid constraint: the type used for the constraint is sealed, which means the constraint could only be satisfied by at most one solution

这似乎与 this mailing list 中讨论的情况相同. Don Syme 说了以下内容:

This is a restriction imposed to make F# type inference tractable. In particular, the type on the right of a subtype constraint must be nominal. Note constraints of the form 'A :> 'B are always eagerly solved to 'A = 'B, as specified in section 14.5.2 (Solving Subtype Constraints) of the F# specification.

您始终可以通过在传递给构建器的函数中使用 obj 来解决此问题。
编辑:即使您使用obj,使用let! 绑定(bind)的值也会有更具体的类型(当调用finallyAction, F# 会自动将某些类型参数的值转换为 obj):

type FinallyBuilder(finallyAction : obj -> unit) =  
member x.Bind(v, f) =
try f v
finally finallyAction v
member x.Return(v) = v

let cleanup = FinallyBuilder(printfn "%A")

let res =
cleanup { let! a = new System.Random()
let! b = "hello"
return 3 }

关于c# - 如何将 `where T : U` 泛型类型参数约束从 C# 转换为 F#?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4173283/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com