如何在f#中声明泛型参数?



给定以下代码:

let DisplayImpl logger data =
    data |> Seq.iter logger
    printfn ""
let Working =
    DisplayImpl (printfn "%O") [1;2;3]
    DisplayImpl (printfn "%O") ["a";"b";"c"]
let NotWorking display =
    display (printfn "%O") [1;2;3]
    display (printfn "%O") ["a";"b";"c"]
                            ~~~ ~~~ ~~~

最后一行给出错误:This expression was expected to have type int but here has type string

我原以为下面的代码可以,但是不行:

let StillNotWorking (display: ('a -> unit) -> seq<'a> -> unit) =

我的问题是,我如何定义NotWorking函数,使显示参数在函数内保持通用?

作为参数传递给其他函数(如您的display)的函数本身在f#中不能是多态的。它们可以使用泛型类型参数('a等),但是这个参数的实际类型是在调用主函数(在您的例子中是NotWorking)时指定的。这意味着您只能使用NotWorking主体中的类型变量'a的单一实际类型调用display

作为一种解决方法,您可以使用带有泛型方法的接口:

type Displayer = 
  abstract Display : (obj -> unit) -> 'T list -> unit
 
let NotWorking (display:Displayer) = 
    display.Display (printfn "%O") [1;2;3] 
    display.Display (printfn "%O") ["a";"b";"c"] 

接口的Display方法本身就是一个泛型方法,因此您可以使用不同类型的参数多次调用该方法(第一种是int,第二种是string)。

然而,当我经常在f#中编写正常代码时,我没有发现这是一个限制,所以也许有一个更容易的解决方案来解决你的问题(可能,采取非通用的IEnumerable或像那样简单的东西-或obj list,如约翰的答案)。如果你能给出更多关于实际代码的细节,那将会很有用。

一些背景,以防你对理论细节感兴趣,但这些在日常的现实世界f#编程中都不重要。无论如何-

这在Haskell等其他语言中是可能的,允许它的机制被称为通用类型。当你在f#中有一个多态函数时,它本质上意味着类型变量的作用域是整个函数,所以('a -> unit) -> unit可以被视为forall 'a . ('a -> unit) -> unit

当你调用函数时,你需要指定'a是什么,并且不能改变(即,一旦'a固定,你就不能使用函数'a -> unit作为'a的两种不同类型的参数)。

使用通用类型,您可以自己编写forall,因此您可以说类型为:
(forall 'a . 'a -> unit) -> unit。现在,通用形参'a只链接到作为实参的函数。作为参数给出的函数的类型现在本身是一个泛型函数,因此您可以使用代表'a的不同类型调用它。

PS:值限制是一个不同的问题-这本质上意味着f#不能使非语法函数的东西泛型,但在您的示例中,您正在编写语法函数,所以这不是这里的问题。

也可以

let NotWorking (display:(obj -> unit) -> obj list -> unit) =
    display (printfn "%O") [1;2;3]
    display (printfn "%O") ["a";"b";"c"]

相关内容

  • 没有找到相关文章

最新更新