Как ограничить параметр типа должен быть алгебраическим типом (int, float, BigInteger, BigRational, ...) - PullRequest
0 голосов
/ 25 января 2019

- Хотя в сети есть несколько вопросов. Ограничения типов уже не найдены, и я не смогу решить проблему -

Цель: я хочу создать свои собственные типы 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>. Как я мог сделать это правильно?

Большое спасибо заранее, Christian.

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Я думаю, все, что вам нужно, это ключевое слово inline, если вы просто хотите распространить ограничения членов перегруженных арифметических операторов F #.

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 s того же типа, которые поддерживают статический член (+), Foo 3 + Foo 4 или Foo 3.14 + Foo 3.14, даже Foo(Foo 3) + Foo(Foo 4);но не Foo 3 + Foo 3.14.Вы все еще можете создавать экземпляры типов, которые не имеют такого члена.

0 голосов
/ 25 января 2019

На самом деле это почти у вас есть.

Чтобы создать функцию, которая принимает любой тип с оператором +, эта функция должна иметь статически разрешенных параметров типа (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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...