理解F#静态成员约束(构造小于一般警告)

时间:2017-09-17 12:23:40

标签: .net static f# inline type-constraints

另一个成员建议的这段代码允许fmap通常与Option和Choice编译并完美地工作,然而有一个警告我正在努力理解和修复。最后一行,在“Functor”下:

此构造导致代码小于泛型。类型变量'b已被约束为Functor。

type Functor = Functor
    with 
    static member FMap (Functor, mapper : 'T -> 'U, opt : Option<'T>) : Option<'U> =
        Option.map mapper opt
    static member FMap (Functor, mapper : 'T -> 'U, ch : Choice<'T, _>) : Choice<'U, _> =
        match ch with
        |Choice1Of2 v -> Choice1Of2 (mapper v)
        |Choice2Of2 v -> Choice2Of2 v

let inline fmap (f : ^c -> ^d ) (x : ^a) =
    ((^b or ^a) : (static member FMap : ^b * ( ^c -> ^d ) * ^a -> ^e ) (Functor, f, x))

这种情况很有意义,因为^ b应该始终是Functor。

我想重新编写代码以解决此警告,但未成功。

为此,为什么我需要(^ b或^ a)而不仅仅是^ a,因为^ b将始终是一个Functor。我没有得到没有(^ b或^ a)语法的编译版本。

此外,为什么有必要通过Functor union case。再一次,我一直无法理解和解决的问题。

欣赏任何清晰度。

1 个答案:

答案 0 :(得分:1)

您只需添加#nowarn "0064"或添加内部调用函数即可解决此警告:

let inline fmap (f :'c->'d) (x : 'a) : 'e = 
    let inline call (mthd : ^B, x : ^A) =
        ((^B or ^A) : (static member FMap: _ * (^c -> ^d ) * ^A -> ^e) (mthd, f, x))
    call (Unchecked.defaultof<Functor>, x)

添加了在调用之前未解决的其他类型变量,对于类型推断,这种方式并不明显,B是a,A是a,B是Functor。

您需要^B or ^A,因为它需要在Functor类型中查找静态方法(对于预先存在的类型,如Option和Choice),还需要查找由^A表示的未来类型定义,允许您稍后在代码中添加如下内容:

type MyType<'a> = MyType of 'a with
    static member FMap (Functor, mapper, MyType a) = MyType (mapper a)

仍然适用于:

> fmap string (MyType 4) ;;
val it : MyType<string> = MyType "4"

最后值得一提的是,这项技术是由一个实验项目(通过观察并试图模仿+运算符的约束)开创和改进的,现在它是F#+的通用模块的一部分。 ,因此您可以找到更多complex examples there,包括“默认实施”。