注意:我在末尾添加了许多Of interest注释。这些并不是要建议一个人使用inlinestatic type parameters willy nilly,所以他们不必花大量时间搜索与该问题相关的大量SO问题就可以更好地理解这些概念。

我知道,当需要使函数通用并且需要零(0)值时,F#提供GenericZero



因此,这使我相信使用字符串类型的GenericZero只需添加一个名为Zero的静态成员。

由于System.String是.Net框架的一部分,因此不应修改.Net源代码。但是F#提供了Type Extensions



F#还提供了String module,但是缺少GenericZero。

有关创建类型扩展的良好教程,请引用:Attaching functions to types

我测试过的代码:

这在一个名为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

因此,我正在创建和访问扩展成员,并使用GenericZero没有任何问题。

最后一部分是对字符串使用GenericZero,但是取消注释行
let stringAdd = addTest "a" LanguagePrimitives.GenericZero

导致错误:



我确实检查了F# spec,但没有发现任何帮助。

我可以将GenericZero添加为System.String类型吗,我在代码中做错了什么吗?还是我错过了文档中的某些内容?

TL; DR

这样搜索时感兴趣的问题

F# - How do I extend a type with get_Zero so I can use an existing type generically?
该IMO是一个误导性标题,应在阅读答案后进行更改。

What/where is get_Zero in F#'s int?
jack 有一个很好的评论:



感兴趣的F#文档

Automatic Generalization



Type Inference



Generics



Statically Resolved Type Parameters



Constraints

Inline Functions



编辑

这是一个示例,它使用GenericZero作为用户定义的类型,而不使用有效的扩展名,并且两个变体表明GenericZerointrinsic extensionoptional extension不起作用

首先运行程序以查看GenericZero的工作原理,然后取消注释Program.fs中的行以查看intrinsic extensionoptional extension的错误。



在项目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/

10-09 03:12