Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resolve the strange type error in a recursive map with statically resolved type parameters?

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 ", "

In the line static member inline PrintArg(_: ArgsPrinter, (x1, x2, x3)) =, the expression (x1, x2, x3) gives me the following error:

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

Any idea what to do here to make this work?

like image 933
Marko Grdinić Avatar asked Jan 23 '17 13:01

Marko Grdinić


1 Answers

It looks to me that you want to do something like this:

    ...

    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 ", "

You define the generic function in the middle of the type because you will use it for the last two overloads, which will become kind of 'recursive overloads'.

Note that this the technique used currently in FSharpPlus, actually a simplification of the technique.

Finally note that your solution seems also correct to me (although more verbose) but for some reason the F# compiler get confused, I can't explain you why but have met many situations like this one and all I can do is find a minimal repro, a workaround and report it to the F# guys. There's still lot of things to be solved in the Constraint Solver.

like image 189
Gus Avatar answered Oct 21 '22 05:10

Gus