了解 F# 静态成员约束(构造小于泛型警告)
Understanding F# static member constraints (Construct less than generic warning)
另一位成员建议的这段代码允许 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。同样,我一直无法理解和解决的问题。
欣赏任何清晰度。
您只需添加一个 #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"
最后值得一提的是,这项技术是由一个实验项目(通过观察并尝试模仿 +
运算符的约束)开创和完善的,该项目现在是 [=17 的通用模块的一部分=] 包括 "default implementations".
另一位成员建议的这段代码允许 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。同样,我一直无法理解和解决的问题。
欣赏任何清晰度。
您只需添加一个 #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"
最后值得一提的是,这项技术是由一个实验项目(通过观察并尝试模仿 +
运算符的约束)开创和完善的,该项目现在是 [=17 的通用模块的一部分=] 包括 "default implementations".