如果我有一个带有通用字段的记录,有没有办法在更改泛型时模仿方便的with
语法?
即。如果我有
type User<'photo> = // 'photo can be Bitmap or Url
{ first: string; last: string; address: string; phone: string; photo: 'photo }
我希望能够写出类似
的内容let loadUser(user: User<Url>): User<Bitmap> =
{ user with
photo = download user.photo }
但看起来我必须写这个。
let loadUser(user: User<Url>): User<Bitmap> =
{ first = user.first
last = user.last
address = user.address
phone = user.phone
photo = download user.photo }
有没有办法获得第一种语法?
答案 0 :(得分:5)
不是直接但您可以将User
变成仿函数(对于photo
部分):
let fmap (f : 'a -> 'b) (user: User<'a>): User<'b> =
{ first = user.first
last = user.last
address = user.address
phone = user.phone
photo = f user.photo }
一次并写(例如):
let loadUser (user : User<Url>) : User<Bitmap> =
fmap download user
如果您愿意fmap
,也可以将 withPhoto
重命名为let loadUser = withPhoto download
:D
现在可能有点奇怪photo
部分是任何类型的数据/类型所以我会考虑将此部分重新命名为value
- 但这只是我
答案 1 :(得分:4)
遗憾的是{ with .. }
语法不能处理类型更改时的情况(虽然我认为可以添加,但可以随意在F#用户语音页面上打开建议!)
添加map
函数有效,但另一种方法是在类型上定义With
方法。这可以为非通用字段采用可选参数。对于通用字段,你不能完全这样做(因为它会统一类型),但你可以有一个重载:
type User<'TPhoto> =
{ Name : string
Photo : 'TPhoto }
member x.With(photo, ?name) =
{ Name = defaultArg name x.Name; Photo = photo }
member x.With(?name) =
{ Name = defaultArg name x.Name; Photo = x.Photo }
第一种方法是通用的,并返回User
和另一种类型的照片。第二种方法不会更改照片,因此它不是通用的。然后你可以像这样使用它:
let t = { Name = "Tomas"; Photo = 0 }
t.With(photo="img") // Change type of photo
t.With(name="Tomáš") // Change just the name
t.With(photo="img", name="Test") // Change everything