F#泛型类型约束和鸭子打字 [英] F# generic type constraints and duck typing

查看:154
本文介绍了F#泛型类型约束和鸭子打字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现F#鸭打字,我发现,你可以有一个的 F#泛型中的成员约束如下:

  type ListEntryViewModel <'T当'T:(member Name :string)>(model:'T)= 
inherit ViewModelBase()

成员this.Name with get()= model.Name

但是,当我尝试引用该属性时,上述代码不会编译。我收到一个编译器错误:


这段代码不够通用。当^ T
:(成员get_Name:^ T - >字符串)时,类型变量^ T不能一概而论,因为
会跳过它的作用域。


是否可以通过泛型约束实现鸭子打字?

解决方案

最近其中构件约束了在类型声明使用了类似的问题。



我不确定如何纠正样本以使其可以编译,但如果这不可能,我不会感到惊讶。成员约束被设计为与静态解析的类型参数一起使用,特别是与 inline 函数或成员一起使用,并且我不认为它是惯用的F#代码,可以将它们与类型参数



我认为对您的示例更习惯的解决方案是定义一个接口:

  type INamed = 
抽象名称:字符串

类型ListEntryViewModel<'T when'T:> INamed>(model:'T)=
member this.Name = model.Name

(事实上​​, ListEntryViewModel 可能并不需要一个类型参数,可以只取 INAMED 作为构造函数的参数,但)

现在,您仍然可以使用duck输入并使用 ListEntryViewModel 名称属性,但不要实现 INamed 接口!这可以通过编写返回 INamed inline 函数并使用静态成员约束捕获现有的名称属性:

  let inline namedModel< ^ T当^ T:(member name:string)> (模型:^ T)= 
{new IN
member x.Name =
(^ T:(member Name:string)model)}

然后,您可以通过编写创建视图模型 ListEntryViewModel(namedModel someObj中),其中 someObj 不需要实现接口,但只需要 Name 属性。



我更喜欢这种风格,因为通过使用界面,您可以更好地记录您从模型中需要的内容。如果你有其他的对象不适合这个方案,你可以调整它们,但是如果你正在编写一个模型,那么实现一个接口是确保它暴露所有必需功能的好方法。


I'm trying to implement duck typing in F# and I spotted that you can have a member constraint in F# generics as follows:

type ListEntryViewModel<'T when 'T : (member Name : string)>(model:'T) = 
  inherit ViewModelBase()

  member this.Name with get() = model.Name

However, the above code won't compile when I try to reference the property. I get a compiler error:

This code is not sufficiently generic. The type variable ^T when ^T : (member get_Name : ^T -> string) could not be generalized because it would escape its scope.

Is it possible to implement duck typing via a generic constraint?

解决方案

There was a similar question recently where member constraints were used in the type declaration.

I'm not sure how to correct your sample to make it compile, but I would not be surprised if that was not possible. Member constraints are designed to be used with statically resolved type parameters and especially with inline functions or members and I do not think it is idiomatic F# code to use them with type parameters of a class.

I think that a more idiomatic solution to your example would be to define an interface:

type INamed = 
  abstract Name : string

type ListEntryViewModel<'T when 'T :> INamed>(model:'T) =  
  member this.Name = model.Name

(In fact, the ListEntryViewModel probably does not need a type parameter and can just take INamed as a constructor parameter, but there may be some benefit in writing it in this way.)

Now, you can still use duck typing and use ListEntryViewModel on things that have Name property, but do not implement the INamed interface! This can be done by writing an inline function that returns INamed and uses static member constraints to capture the existing Name property:

let inline namedModel< ^T when ^T : (member Name : string)> (model:^T)= 
  { new INamed with
      member x.Name = 
        (^T : (member Name : string) model) }

You can then create your view model by writing ListEntryViewModel(namedModel someObj) where someObj does not have to implement the interface, but needs just the Name property.

I would prefer this style, because by taking an interface, you can better document what you require from the model. If you have other objects that do not fit the scheme, you can adapt them, but if you're writing a model, then implementing an interface is a good way to make sure it exposes all the required functionality.

这篇关于F#泛型类型约束和鸭子打字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆