【问题标题】:Understanding F# static member constraints (Construct less than generic warning)了解 F# 静态成员约束(构造小于泛型警告)
【发布时间】:2018-02-26 02:09:46
【问题描述】:

另一位成员建议的这段代码允许 fmap 一般与 Option 和 Choice 一起工作,编译并完美运行,但是有一个警告我正在努力理解和修复。最后一行,在“函子”下:

这种结构会导致代码不够通用。类型变量 '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。再次,我无法理解和解决的问题。

感谢任何清晰。

【问题讨论】:

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


    【解决方案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,包括“默认实现”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-29
      • 2019-06-10
      相关资源
      最近更新 更多