首页 > 解决方案 > 如何约束类型参数必须是代数类型(int、float、BigInteger、BigRational、...)

问题描述

- 虽然网上有一些问题。类型约束已经,我没有找到可以帮助我解决问题的约束。--

目标:我想创建自己的 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>. 我怎么能做对?

非常感谢,克里斯蒂安。

标签: f#

解决方案


实际上,您几乎拥有它。

为了创建一个接受具有+运算符的任何类型的函数,该函数必须具有静态解析类型参数(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

推荐阅读