开发者

F#: Can't hide a type abbreviation in a signature? Why not?

In F#, I'd like to have what I see as a fairly stand开发者_C百科ard Abstract Datatype:

// in ADT.fsi
module ADT
  type my_Type

// in ADT.fs
module ADT
  type my_Type = int

In other words, code inside the module knows that my_Type is an int, but code outside does not. However, F# seems to have a restriction where type abbreviations specifically cannot be hidden by a signature. This code gives a compiler error, and the restriction is described here.

If my_Type were instead a discriminated union, then there is no compiler error. My question is, why the restriction? I seem to remember being able to do this in SML and Ocaml, and furthermore, isn't this a pretty standard thing to do when creating an abstract datatype?

Thanks


As Ganesh points out, this is a technical limitation of the F# compiler (and .NET runtime), because the type abbreviation is simply replaced by the actual type during the compilation. As a result, if you write a function:

let foo (a:MyType) : MyType = a + 1

The compiler will compile it as a .NET method with the following signature:

int foo(int a);

If the actual type of the abbreviation was hidden from the users of the library, then they wouldn't be able to recognize that the foo function is actually working with MyType (this information is probably stored in some F#-specific meta-data, but that is not accessible to other .NET languages...).

Perhaps the best workaround for this limiation is to define the type as a single-case discriminated union:

type MyType = MT of int
let foo (MT a) = MT(a + 1)

Working with this kind of type is quite convenient. It adds some overhead (there are new objects created when constructing a value of the type), but that shouldn't be a big issue in most of the situations.


Type abbreviations in F# are compiled away (i.e. the compiled code will use int, not MyType), so you can't make them properly abstract. In theory the compiler could enforce the abstraction within the F# world, but this wouldn't be very helpful as it would still leak in other languages.


Note that you can define a type abbreviation as private within a module:

// File1.fs
module File1
    type private MyType = int 
    let e : MyType = 42
    let f (x:MyType) = x+1

// Program.fs
module Program
do printfn "%A" (File1.f File1.e)

I am unclear why you can't hide it with a signature; I logged a bug to consider it.


From what I understand F# does not allow an abbreviation to be hidden by a signature.

I found this link where the blogger commented on this but I am not sure on the specifics of why this is the case.

My assumption is that this is a restraint set to allow more effective interop with other languages on the CLR.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜