简体   繁体   English

F# 模块中的通用值?

[英]Generic values in F# modules?

Consider a generic container like:考虑一个通用容器,如:

type Foo<'t> = 
  {
    Foo : 't
  }

This generic function works OK:这个通用函数可以正常工作:

module Foo = 
  
  let inline emptyFoo () = 
    {
      Foo = LanguagePrimitives.GenericZero
    }

But this value does not:但是这个值不会:

module Foo = 
  
  let emptyFoo = 
    {
      Foo = LanguagePrimitives.GenericZero
    }

This is because the compiler infers emptyFoo to have type Foo<obj> .这是因为编译器推断emptyFoo具有Foo<obj>类型。

However, the standard library has generic values like List.empty , so how is that achieved there?然而,标准库有像List.empty这样的通用值,那么它是如何实现的呢?

You have to make it explicitly generic.您必须使其明确通用。

List.empty is implemented like this : List.empty实现像这样

let empty<'T> = ([ ] : 'T list)

You could implement a List by yourself, with an empty.你可以自己实现一个 List ,一个空的。 It looks like this.它看起来像这样。

type L<'a> =
    | Null
    | Cons of 'a * L<'a>

module L =
    let empty = Null

let xs = Cons(1,  Cons(2,  L.empty))
let ys = Cons(1.0,Cons(2.0,L.empty))

So, why does L.empty in this case works in a generic way?那么,为什么L.empty在这种情况下以通用方式工作? Because the value Null has no special value attached to it.因为值Null没有附加任何特殊值。 You could say, it is compatible with every other generic.你可以说,它与所有其他泛型兼容。

In your Record on the other hand, you always must produce a value.另一方面,在您的 Record 中,您始终必须产生一个值。 LanguagePrimitive.GenericZero is not some Generic value. LanguagePrimitive.GenericZero不是一些 Generic 值。 It help so to resolve to a special zero value, and this value is determined by the other code you write.解析为一个特殊的零值是有帮助的,这个值是由你编写的其他代码决定的。

For example例如

let x = LanguagePrimitives.GenericZero

is also obj也是obj

let x = LanguagePrimitives.GenericZero + 1

will be int .将是int And

let x = LanguagePrimitives.GenericZero + 1.0

will be float .float So in some case you can think of GenericZero just as a placeholder for zero for the special type you need, but the code needs to determine at this point, which type you want.因此,在某些情况下,您可以将GenericZero视为您需要的特殊类型的零占位符,但此时代码需要确定您想要哪种类型。

You could change your type, with an option to provide a real empty.您可以更改您的类型,并选择提供一个真正的空。

type Foo<'t> = {
    Foo: 't option
}

module Foo =
    let empty = { Foo = None }

let x = Foo.empty                  // Foo<'a>
let y = { x with Foo = Some 1   }  // Foo<int>
let z = { x with Foo = Some 1.0 }  // Foo<float>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM