-虽然网上有一些问题。类型约束已经存在,我找不到能帮助我解决问题的约束。 -
目标:我想创建自己的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>
。我该怎么办?
非常感谢, 基督徒。
答案 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 4
或Foo 3.14 + Foo 3.14
,甚至Foo(Foo 3) + Foo(Foo 4)
;但Foo 3 + Foo 3.14
除外。您仍然可以实例化不具有该成员的类型。