如何限制类型参数必须是代数类型(int,float,BigInteger,BigRational等)

时间:2019-01-25 07:21:39

标签: f#

-虽然网上有一些问题。类型约束已经存在,我找不到能帮助我解决问题的约束。 -

目标:我想创建自己的Vector / Matrix类型,但是这样,该实现就不会锁定到特定的BigRational(或类似)类型。我只想对这种类型(+-* /%相等)进行标准的代数运算。

open System

type Foo<'T> (value: 'T) =
    member inline __.Value : 'T = value

    static member inline Add (a: Foo<'T>) (b: Foo<'T>) =
        Foo<'T>(a.Value + b.Value)

module Foo =
    let inline Create (v) = Foo(v)

    let log (foo: #Foo<_>) =
        printfn "Foo: %s" (foo.Value.ToString())

[<EntryPoint>]
let main argv =
    Foo.log (Foo.Create("hi ho"))
    Foo.log (Foo<int>(31415))
    Foo.log (Foo<float>(3.1415))
    Foo.log (Foo<int>.Add (Foo.Create(3)) (Foo.Create(4)))
    let a = Foo.Create(13)
    let b = Foo.Create(3.1415)
    Foo.log (Foo<int>.Add (a.Value) (a.Value))
    Foo.log (Foo<float>.Add (b.Value) (b.Value))
    0 // return an integer exit code

我无法获得这个小小的示例代码来为多个类型进行编译,例如Foo<int>Foo<float>。我该怎么办?

非常感谢, 基督徒。

2 个答案:

答案 0 :(得分:2)

实际上,您几乎拥有它。

为了创建一个接受具有+运算符的任何类型的函数,此函数必须具有statically-resolved type parameters(SRTP)。为此,它必须是内联的,您的Add是可以的。但是,这里的Add不是通用方法:它是通用类型Foo<'T>上的方法,因此它从中接收其'T参数。而且类型不能具有SRTP。

一个简单的解决方法是将Add从类型为Foo<'T>的方法转变为模块Foo中的函数。然后它将变成通用。

open System

type Foo<'T> (value: 'T) =
    member inline __.Value : 'T = value

module Foo =
    let inline Create (v) = Foo(v)

    let inline Add (a: Foo< ^T>) (b: Foo< ^T>) =
        Foo< ^T>(a.Value + b.Value)

    let log (foo: #Foo<_>) =
        printfn "Foo: %s" (foo.Value.ToString())

[<EntryPoint>]
let main argv =
    Foo.log (Foo.Create("hi ho"))
    Foo.log (Foo<int>(31415))
    Foo.log (Foo<float>(3.1415))
    Foo.log (Foo.Add (Foo.Create(3)) (Foo.Create(4)))
    let a = Foo.Create(13)
    let b = Foo.Create(3.1415)
    Foo.log (Foo.Add a a)
    Foo.log (Foo.Add b b)
    0

答案 1 :(得分:0)

如果您只想传播F#重载算术运算符的成员约束,我想您只需要inline关键字。

type Foo<'T> (value : 'T) =
    member __.Value = value
    static member inline (+) (a : Foo<_>, b : Foo<_>) = Foo(a.Value + b.Value)
    // static member
    //   ( + ) : a:Foo< ^a> * b:Foo< ^b> -> Foo< ^c>
    //             when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)

现在,您可以添加两个相同类型的Foo,它们支持静态成员(+)Foo 3 + Foo 4Foo 3.14 + Foo 3.14,甚至Foo(Foo 3) + Foo(Foo 4);但Foo 3 + Foo 3.14除外。您仍然可以实例化不具有该成员的类型。