如何使用静态解析的类型参数解析递归映射中的奇怪类型错误?

时间:2017-01-23 13:07:06

标签: generics static f# inline

type CudaInnerExpr<'t> = CudaInnerExpr of expr: string with
    member t.Expr = t |> fun (CudaInnerExpr expr) -> expr

type CudaScalar<'t> = CudaScalar of name: string with
    member t.Name = t |> fun (CudaScalar name) -> name

type CudaAr1D<'t> = CudaAr1D of CudaScalar<int> * name: string with
    member t.Name = t |> fun (CudaAr1D (_, name)) -> name

type CudaAr2D<'t> = CudaAr2D of CudaScalar<int> * CudaScalar<int> * name: string with
    member t.Name = t |> fun (CudaAr2D (_, _, name)) -> name

type ArgsPrinter = ArgsPrinter with
    static member inline PrintArg(_: ArgsPrinter, t: CudaScalar<float32>) = sprintf "float %s" t.Name
    static member inline PrintArg(_: ArgsPrinter, t: CudaScalar<int>) = sprintf "int %s" t.Name
    static member inline PrintArg(_: ArgsPrinter, t: CudaAr1D<float32>) = sprintf "float *%s" t.Name
    static member inline PrintArg(_: ArgsPrinter, t: CudaAr1D<int>) = sprintf "int *%s" t.Name
    static member inline PrintArg(_: ArgsPrinter, t: CudaAr2D<float32>) = sprintf "float *%s" t.Name
    static member inline PrintArg(_: ArgsPrinter, t: CudaAr2D<int>) = sprintf "int *%s" t.Name

    static member inline PrintArg(_: ArgsPrinter, (x1, x2)) = 
        let inline print_arg x = 
            let inline call (tok : ^T) = ((^T or ^in_) : (static member PrintArg: ArgsPrinter * ^in_ -> string) tok, x)
            call ArgsPrinter
        [|print_arg x1;print_arg x2|] |> String.concat ", "
    static member inline PrintArg(_: ArgsPrinter, (x1, x2, x3)) = 
        let inline print_arg x = 
            let inline call (tok : ^T) = ((^T or ^in_) : (static member PrintArg: ArgsPrinter * ^in_ -> string) tok, x)
            call ArgsPrinter
        [|print_arg x1;print_arg x2;print_arg x3|] |> String.concat ", "

static member inline PrintArg(_: ArgsPrinter, (x1, x2, x3)) =行中,表达式(x1, x2, x3)给出了以下错误:

Script1.fsx(26,52): error FS0001: This expression was expected to have type
    'in_    
but here has type
    'a * 'b * 'c

知道该怎么做才能让这个工作吗?

1 个答案:

答案 0 :(得分:9)

在我看来,你想做这样的事情:

    ...

    static member inline PrintArg(_: ArgsPrinter, t: CudaAr2D<float32>) = sprintf "float *%s" t.Name
    static member inline PrintArg(_: ArgsPrinter, t: CudaAr2D<int>) = sprintf "int *%s" t.Name

let inline print_arg x =
    let inline call (tok : ^T) = ((^T or ^in_) : (static member PrintArg: ArgsPrinter * ^in_ -> string) tok, x)
    call ArgsPrinter       

type ArgsPrinter with
    static member inline PrintArg(_: ArgsPrinter, (x1, x2)) = [|print_arg x1;print_arg x2|] |> String.concat ", "
    static member inline PrintArg(_: ArgsPrinter, (x1, x2, x3)) = [|print_arg x1;print_arg x2;print_arg x3|] |> String.concat ", "

您可以在类型的中间定义泛型函数,因为您将使用它来进行最后两次重载,这将成为“递归重载”。

请注意,这是FSharpPlus中当前使用的技术,实际上是该技术的简化。

最后请注意,你的解决方案对我来说似乎也是正确的(虽然更详细)但由于某些原因F#编译器感到困惑,我无法解释你为什么但是遇到了很多像这样的情况,我所能做的就是找到一个最小的repro,一个解决方法,并报告给F#家伙。在Constraint Solver中还有很多事情需要解决。