F # 4.5.0.0: Ошибки компиляции: FS1198, FS0661 и FS0001: я адаптирую интерфейс с C# на F # - PullRequest
1 голос
/ 17 апреля 2020

Моя цель - портировать FSharp.Core версии 4.5.0.0 на. NET 4.0. Для достижения своей цели я переписываю части Theraot.Core на F #, поскольку FSharp.Core не «принимает» сторонние библиотеки: https://github.com/theraot/Theraot/issues/121.

Я адаптирую интерфейс от C# до F #.

Интерфейс в C#: https://github.com/theraot/Theraot/blob/master/Framework.Core/System/Collections/Generic/IReadOnlyDictionary.cs

Введите F #:

namespace System.Collections.Generic

open Microsoft.FSharp.Core

type IReadOnlyCollection<'T> =
    inherit IEnumerable<'T>

    abstract Count : int with get

type IReadOnlyDictionary<'TKey, 'TValue> =
    inherit IReadOnlyCollection<KeyValuePair<'TKey, 'TValue>>

    abstract Keys : IEnumerable<'TKey> with get
    abstract Values : IEnumerable<'TValue> with get
    abstract Item : key : 'TKey -> 'TValue with get
    abstract ContainsKey : key : 'TKey -> bool
    abstract TryGetValue : key : 'TKey * [<System.Runtime.InteropServices.Out>] value : byref<'Value> -> bool

Где ошибки компиляции происходит: https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/map.fs#L626 https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/fslib-extra-pervasives.fs#L88

Когда в C# до F # работает отлично, но возникают ошибки компиляции от F # до F #:

map.fs:

FS1198 Типовой член c TryGetValue использовался в неоднородном экземпляре до этой программной точки. Подумайте о переупорядочении членов, чтобы этот элемент появился первым. В качестве альтернативы можно явно указать полный тип члена, включая типы аргументов, тип возвращаемого значения и любые дополнительные универсальные c параметры и ограничения.

FS0661 Одна или несколько явных переменных класса или типа функции для этой привязки могут не следует обобщать, поскольку они были ограничены другими типами.

fslib-extra-pervasives.fs:

FS0001 Ожидалось, что это выражение будет иметь тип '' a '
, но здесь введите '' T '

Я также безуспешно пытался:

abstract TryGetValue : key : 'TKey * [<System.Runtime.InteropServices.Out>] value : 'Value -> bool

Редактировать: я делаю свои первые шаги в F #. Единственная информация, которую я обнаружил, заключалась в том, что неизменность F # - это очень круто, но иногда невозможно написать F # как C#.

Первые две ошибки компилятора, которые я не знаю, откуда они появились, но третий можно упростить:

namespace TestBugApplication1

open System.Collections.Generic

type DictImpl<'SafeKey,'Key,'T>(t : Dictionary<'SafeKey,'T>, makeSafeKey : 'Key->'SafeKey) =
    interface IReadOnlyDictionary<'Key, 'T> with
        member this.ContainsKey(key) = raise (System.NotImplementedException())
        member this.Count = raise (System.NotImplementedException())
        member this.GetEnumerator() = raise (System.NotImplementedException())
        member this.GetEnumerator() = raise (System.NotImplementedException())
        member this.Item
            with get (key) = raise (System.NotImplementedException())
        member this.Keys = raise (System.NotImplementedException())
        member this.TryGetValue(key, r) =
            match t.TryGetValue (makeSafeKey key) with
                            | false, _ -> false
                            | true, value ->
                                r <- value //<- Compiler error
                                true
        member this.Values = raise (System.NotImplementedException())

Я также могу отправить ссылку на скачивание с решением, которое я программирую.

1 Ответ

1 голос
/ 18 апреля 2020

Ваша проблема не в реализации, а в определении IReadOnlyDictionary.

abstract TryGetValue : key : 'TKey * [<Out>] value : byref<'Value> -> bool

Обратите внимание, что это 'Value. Это означает, что TryGetValue будет иметь подпись TryGetValue<V>(TKey key, out V value) вместо TryGetValue(TKey key, out TValue value).

Если исправить его на

abstract TryGetValue : key : 'TKey * [<Out>] value : byref<'TValue> -> bool

, то он будет скомпилирован.

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

member this.GetEnumerator() : IEnumerator<KeyValuePair<'Key, 'T>> = 
    raise (System.NotImplementedException())

member this.GetEnumerator() : IEnumerator = 
    raise (System.NotImplementedException())
...