- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
注意:我在末尾添加了许多Of interest
注释。这些并不是要建议一个人使用inline
和static type parameters
willy nilly,所以他们不必花大量时间搜索与该问题相关的大量SO问题就可以更好地理解这些概念。
我知道,当需要使函数通用并且需要零(0)值时,F#提供GenericZero。
Resolves to the zero value for any primitive numeric type or any type with a static member called Zero.
GenericZero
只需添加一个名为Zero的静态成员。
Type extensions let you add new members to a previously defined object type.
Library1
的项目中
namespace Extension.Test
module Extensions =
type System.String with
static member Something = "a"
static member StaticProp
with get() = "b"
static member Zero
with get() = "c"
Workspace
的项目中
namespace Extension.Test
module main =
open Extensions
[<EntryPoint>]
let main argv =
let stringSomething = System.String.Something
printfn "something: %s" stringSomething
let staticProperty = System.String.StaticProp
printfn "staticProperty: %s" staticProperty
let zeroProperty = System.String.Zero
printfn "zeroProperty: %s" zeroProperty
let inline addTest (x : ^a) (y : ^a) : ^a =
x + y
let intAdd = addTest 2 LanguagePrimitives.GenericZero
let floatAdd = addTest 2.0 LanguagePrimitives.GenericZero
// let stringAdd = addTest "a" LanguagePrimitives.GenericZero
printfn "intAdd: %A" intAdd
printfn "floatAdd: %A" floatAdd
// printfn "stringAdd: %A" stringAdd
printf "Press any key to exit: "
System.Console.ReadKey() |> ignore
printfn ""
0 // return an integer exit code
something: a
staticProperty: b
zeroProperty: c
intAdd: 2
floatAdd: 2.0
Press any key to exit
let stringAdd = addTest "a" LanguagePrimitives.GenericZero
The type 'string' does not support the operator 'get_Zero'
System.String
类型吗,我在代码中做错了什么吗?还是我错过了文档中的某些内容?
Zero doesn't make sense on string if you think of it in terms of numerics; however, it does make sense to have a Zero member on string which returns the empty string, as that would make string a monoid under string concatenation.
The F# compiler, when it performs type inference on a function, determines whether a given parameter can be generic. The compiler examines each parameter and determines whether the function has a dependency on the specific type of that parameter. If it does not, the type is inferred to be generic.
The idea of type inference is that you do not have to specify the types of F# constructs except when the compiler cannot conclusively deduce the type.
For those types that you do not specify explicitly, the compiler infers the type based on the context. If the type is not otherwise specified, it is inferred to be generic.
F# function values, methods, properties, and aggregate types such as classes, records, and discriminated unions can be generic. Generic constructs contain at least one type parameter, which is usually supplied by the user of the generic construct. Generic functions and types enable you to write code that works with a variety of types without repeating the code for each type. Making your code generic can be simple in F#, because often your code is implicitly inferred to be generic by the compiler's type inference and automatic generalization mechanisms.
A statically resolved type parameter is a type parameter that is replaced with an actual type at compile time instead of at run time. They are preceded by a caret (^) symbol.
Statically resolved type parameters are primarily useful in conjunction with member constraints, which are constraints that allow you to specify that a type argument must have a particular member or members in order to be used. There is no way to create this kind of constraint by using a regular generic type parameter.
In the F# language, there are two distinct kinds of type parameters. The first kind is the standard generic type parameter. These are indicated by an apostrophe ('), as in 'T and 'U. They are equivalent to generic type parameters in other .NET Framework languages. The other kind is statically resolved and is indicated by a caret symbol, as in ^T and ^U.
When you use static type parameters, any functions that are parameterized by type parameters must be inline.
GenericZero
作为用户定义的类型,而不使用有效的扩展名,并且两个变体表明
GenericZero
对
intrinsic extension
和
optional extension
不起作用
GenericZero
的工作原理,然后取消注释
Program.fs
中的行以查看
intrinsic extension
和
optional extension
的错误。
An intrinsic extension is an extension that appears in the same namespace or module, in the same source file, and in the same assembly (DLL or executable file) as the type being extended.
An optional extension is an extension that appears outside the original module, namespace, or assembly of the type being extended. Intrinsic extensions appear on the type when the type is examined by reflection, but optional extensions do not. Optional extensions must be in modules, and they are only in scope when the module that contains the extension is open.
Library1.fs
中的
Library1
中
namespace Extension.Test
module module001 =
// No extension
type MyType01(x: string) =
member this.x = x
override this.ToString() = this.x.ToString()
static member Something = MyType01("a")
static member (+) (mt1 : MyType01, mt2 : MyType01) = MyType01(mt1.x + mt2.x)
static member (+) (mt1 : MyType01, s : string) = MyType01(mt1.x + s)
static member (+) (s : string, mt2 : MyType01) = MyType01(s + mt2.x)
static member Zero
with get() = MyType01("b")
// uses intrinsic extension
type MyType02(x: string) =
member this.x = x
override this.ToString() = this.x.ToString()
static member Something = MyType02("g")
static member (+) (mt1 : MyType02, mt2 : MyType02) = MyType02(mt1.x + mt2.x)
static member (+) (mt1 : MyType02, s : string) = MyType02(mt1.x + s)
static member (+) (s : string, mt2 : MyType02) = MyType02(s + mt2.x)
// static member Zero
// with get() = MyType02("h")
// uses optional extension
type MyType03(x: string) =
member this.x = x
override this.ToString() = this.x.ToString()
static member Something = MyType03("m")
static member (+) (mt1 : MyType03, mt2 : MyType03) = MyType03(mt1.x + mt2.x)
static member (+) (mt1 : MyType03, s : string) = MyType03(mt1.x + s)
static member (+) (s : string, mt2 : MyType03) = MyType03(s + mt2.x)
// static member Zero
// with get() = MyType03("n")
module module002 =
open module001
// intrinsic extension
type MyType02 with
static member Zero
with get() = MyType02("h")
Library2.fs
中的
Library2
中
namespace Extension.Test
open module001
module module003 =
type MyType01 with
static member Anything = MyType02("c")
type MyType02 with
static member Anything = MyType02("i")
// optional extension
type MyType03 with
static member Anything = MyType03("p")
static member Zero
with get() = MyType03("n")
Program.fs
中的
Workspace
中
namespace Workspace
open Extension.Test.module001
open Extension.Test.module002
open Extension.Test.module003
module main =
[<EntryPoint>]
let main argv =
let staticFromBaseType = MyType01.Something
printfn "MyType01 staticFromBaseType: %A" staticFromBaseType
let staticFromExtensionType = MyType01.Anything
printfn "MyType01 staticFromExtensionType: %A" staticFromExtensionType
let zeroValue = MyType01.Zero
printfn "MyType01 zeroValue: %A" zeroValue
let (genericZero: MyType01) = LanguagePrimitives.GenericZero
printfn "MyType01 genericZero: %A" genericZero
let staticFromBaseType = MyType02.Something
printfn "MyType02 staticFromBaseType: %A" staticFromBaseType
let staticFromExtensionType = MyType02.Anything
printfn "MyType02 staticFromExtensionType: %A" staticFromExtensionType
let zeroValue = MyType02.Zero
printfn "MyType02 zeroValue: %A" zeroValue
// let (genericZero: MyType02) = LanguagePrimitives.GenericZero
// printfn "MyType02 genericZero: %A" genericZero
let staticFromBaseType = MyType03.Something
printfn "MyType03 staticFromBaseType: %A" staticFromBaseType
let staticFromExtensionType = MyType03.Anything
printfn "MyType03 staticFromExtensionType: %A" staticFromExtensionType
let zeroValue = MyType03.Zero
printfn "MyType03 zeroValue: %A" zeroValue
// let (genericZero: MyType03) = LanguagePrimitives.GenericZero
// printfn "MyType03 genericZero: %A" genericZero
let inline addTest (x : ^a) (y : ^a) : ^a =
x + y
let intAdd = addTest 2 LanguagePrimitives.GenericZero
let floatAdd = addTest 2.0 LanguagePrimitives.GenericZero
let (myType01Add : MyType01) = addTest (MyType01("d")) LanguagePrimitives.GenericZero
// let (myType02Add : MyType02) = addTest (MyType02("d")) LanguagePrimitives.GenericZero
// let (myType03Add : MyType03) = addTest (MyType03("o")) LanguagePrimitives.GenericZero
printfn "intAdd: %A" intAdd
printfn "floatAdd: %A" floatAdd
printfn "myType01Add: %A" myType01Add
// printfn "myType02Add: %A" myType02Add
// printfn "myType03Add: %A" myType03Add
printf "Press any key to exit: "
System.Console.ReadKey() |> ignore
printfn ""
0 // return an integer exit code
最佳答案
扩展成员不被视为成员约束解决方案的一部分,因此您很不走运。对于涉及多个类型的约束(例如(+)
的约束),您可以通过使用第二种类型来解决,但是对于GenericZero
的约束,没有很好的解决方法。
关于generics - 如何将LanguagePrimitives.GenericZero/get_Zero添加到System.String?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37117089/
我是一名优秀的程序员,十分优秀!