如何使用静态解析类型参数解决递归映射中的奇怪类型错误? (第 2 部分)

How to resolve the strange type error in a recursive map with statically resolved type parameters? (pt. 2)

我尝试了两种变体,它们都有同样的问题。

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

type TypePrinter<'t>() = class end

let inline print_type x =
    ((^T or ^in_) : (static member PrintType: TypePrinter< ^in_> -> string) x)

type TypePrinter with
    static member inline PrintType(_: TypePrinter<float32>) = "float32"
    static member inline PrintType(_: TypePrinter<int>) = "int"

type ArgsPrinter = ArgsPrinter
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, t: CudaScalar< ^t>) = 
        [|print_type (TypePrinter< ^t>()); t.Name|] |> String.concat " "

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

type TypePrinter = TypePrinter

let inline print_type x =
    let call (tok: ^T) = ((^T or ^in_) : (static member PrintType: TypePrinter * ^in_ -> string) tok, x)
    call TypePrinter

type TypePrinter with
    static member inline PrintType(_: TypePrinter,_: float32) = "float32"
    static member inline PrintType(_: TypePrinter,_ : int) = "int"

type ArgsPrinter = ArgsPrinter
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, t: CudaScalar< ^t>) = 
        [|print_type Unchecked.defaultof< ^t>; t.Name|] |> String.concat " "

起初我得到了与 中完全相同的错误,但在我删除之后:

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

我在最后 3 行中得到了这个(对于两个变体):

Script1.fsx(16,34): error FS0193: Type constraint mismatch. The type 
    'in_    
is not compatible with type
    FSI_0002.CudaScalar<'a>    
The type ''in_' does not match the type 'FSI_0002.CudaScalar<'a>'

这让我很吃惊,因为错误没有出现在 Intellisense 中,只有当我尝试在 F# Interactive 中 运行 它时才会出现。我不确定再次在这里做什么。我可能过度滥用了类型系统,但我决心以一种或另一种方式以无标记风格完成这个 Cuda 编译器。我需要这样,以便为以后的阶段传播类型信息。

编辑:Gustavo 的修复有效,但当我更进一步时它又坏了。

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 TypePrinter<'t>() = class end

let inline print_type x =
    ((^T or ^in_) : (static member PrintType: TypePrinter< ^in_> -> string) x)

type TypePrinter with
    static member inline PrintType(_: TypePrinter<float32>) = "float32"
    static member inline PrintType(_: TypePrinter<int>) = "int"

type ArgsPrinter = ArgsPrinter with
    static member inline PrintArg(_: ArgsPrinter, t: CudaScalar< ^t>) = 
        [|print_type (TypePrinter< ^t>()); t.Name|] |> String.concat " "
    static member inline PrintArg(_: ArgsPrinter, t: CudaAr1D< ^t>) = 
        [|print_type (TypePrinter< ^t>()); "*"; t.Name|] |> String.concat " "

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

再一次,在最后两行中,我出现了与 pt 中完全相同的错误。其中 1 个。我在这里要做的是制作嵌入式 Cuda DSL 的一部分。我这样做而不是使用 DU 的原因是因为对于 DU,我必须将接口作为一个单独的部分。如果我这样做,我将能够编写 cuda_map (fun x -> x*x) 并编译它,因为类型信息将会存在。上面的片段特别应该打印出内核方法的参数。

如果这是 Haskell 我会使用 typeclasses+HKTs+tagless 风格来做到这一点,在 Ocaml GADTs 中,但在 F# 中,对我来说唯一现实的选择是模仿 finally tagless style 使用静态解析类型参数,但我没有指望有编译器错误。

我打算将此线程传递给我打开的问题。

我不确定我是否理解你的意思question/what你想达到什么目的。

我不知道你为什么要在类型中间插入函数,在你之前的问题中这是必要的,但在这里我不这么认为。

如果你按照自然顺序编写,它会编译:

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

type TypePrinter<'t>() = class end

let inline print_type x =
    ((^T or ^in_) : (static member PrintType: TypePrinter< ^in_> -> string) x)

type TypePrinter with
    static member inline PrintType(_: TypePrinter<float32>) = "float32"
    static member inline PrintType(_: TypePrinter<int>) = "int"

type ArgsPrinter = ArgsPrinter with
    static member inline PrintArg(_: ArgsPrinter, t: CudaScalar< ^t>) = 
        [|print_type (TypePrinter< ^t>()); t.Name|] |> String.concat " "

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

我的意思是,'extending' 两次。