在F#中,我希望得到一个相当标准的抽象数据类型:
// in ADT.fsi
module ADT
type my_Type
// in ADT.fs
module ADT
type my_Type = int
Run Code Online (Sandbox Code Playgroud)
换句话说,模块内部的代码知道my_Type是int,但外部代码不是.但是,F#似乎有一个限制,其中特定的缩写不能被签名隐藏.此代码给出了编译器错误,此处描述了限制.
如果my_Type是一个有区别的联合,那么就没有编译器错误.我的问题是,为什么限制?我似乎记得能够在SML和Ocaml中做到这一点,而且,在创建抽象数据类型时,这不是一个非常标准的事情吗?
谢谢
Tom*_*cek 10
正如Ganesh所指出的,这是F#编译器(和.NET运行时)的技术限制,因为在编译期间类型缩写仅被实际类型替换.因此,如果你写一个函数:
let foo (a:MyType) : MyType = a + 1
Run Code Online (Sandbox Code Playgroud)
编译器将其编译为具有以下签名的.NET方法:
int foo(int a);
Run Code Online (Sandbox Code Playgroud)
如果缩写的实际类型是从库的用户隐藏的,那么他们将无法识别该foo函数实际上正在使用MyType(此信息可能存储在某些F#特定的元数据中,但这是其他.NET语言无法访问...).
也许这种限制的最佳解决方法是将类型定义为单个案例区分联合:
type MyType = MT of int
let foo (MT a) = MT(a + 1)
Run Code Online (Sandbox Code Playgroud)
使用这种类型非常方便.它增加了一些开销(在构造类型的值时会创建新的对象),但在大多数情况下这不应该是一个大问题.
F#中的类型缩写被编译掉(即编译的代码将使用int,而不是MyType),因此您无法使它们正确抽象.理论上,编译器可以在F#世界中强制执行抽象,但这不会非常有用,因为它仍会在其他语言中泄漏.