F#TypeShape-此代码不够通用

  • 本文关键字:不够 代码 F#TypeShape- f#
  • 更新时间 :
  • 英文 :


我正在尝试学习TypeShape库,并根据自述中的片段玩IShapeMember

类型IShapeMember<'DeclaringType,'字段>abstract Get:'声明类型->'领域抽象集:'DeclaringType->'字段->'DeclaringType

这是我的代码,旨在推广"setter"函数

let setMemberValue (value: 'b) (target: 'c) (shp: IShapeMember<'c>) =
shp.Accept { new IMemberVisitor<'c,'c> with
member x.Visit (m: ShapeMember<'c,'b>) = m.Set target value}

但这给了我编译错误:这段代码不够通用。类型变量"a"无法泛化,因为它将脱离其作用域

(顺便说一句,这不是错误的类型,它确实抱怨变量"a…"(

我试过各种类型的争吵,但我无法理解我做错了什么。

我不是TypeShape专家,但我认为这里的问题是你没有遵守Visit函数的签名,即:

type IMemberVisitor<'TRecord, 'R> =
abstract Visit<'Field> : ShapeMember<'TRecord, 'Field> -> 'R

请注意,'Field类型参数由调用Visit的用户决定,而不是由您决定。因此,在对Set的调用中使用外部value的尝试不够通用。相反,您需要一种方法来从Visit函数内的中获得'Field的实例,这样它就可以与调用方想要的任何'Field类型一起使用。这说起来容易做起来难,但如果你想从一个微不足道的例子开始,这将至少编译:

let visitor target =
{
new IMemberVisitor<'TRecord, 'R> with
member x.Visit (m: ShapeMember<'TRecord,'Field>) =
let value = Unchecked.defaultof<'Field>
let target' = m.Set target value
Unchecked.defaultof<'R>
}

这里还有一个从Visit中调用Set的示例,但它更复杂。我认为没有任何方法既简单又有用。

let setMemberValue (value: 'b) (target: 'c) (shp: IShapeMember<'c>) =
shp.Accept { new IMemberVisitor<'c,'c> with
member x.Visit (m: ShapeMember<'c,'d>) = 
if typeof<'b> = typeof<'a> then //or convert 'b -> 'd function
m.Set target (box value :?> 'd)
else 
failwith "The supplied type does not match the type of the target field"
}

将所提供的value装箱并铸造为类型'd起到了作用。如果调用方提供的值与正在设置的字段的值不匹配,则所有内容都以某种形式的类型检查进行包装

最新更新