记录 "with" 语法中的泛型
Generics in record "with" syntax
如果我有一个带有通用字段的记录,在更改通用字段时有什么方法可以模仿方便的 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 }
有没有办法得到第一个语法?
不是直接的,但是你可以将你的 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
部分是任何一种 data/type 可能有点奇怪,所以我会考虑将这部分重新命名为 value
- 但那只是我
遗憾的是,{ 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 }
第一种方法是通用的,returns 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
如果我有一个带有通用字段的记录,在更改通用字段时有什么方法可以模仿方便的 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 }
有没有办法得到第一个语法?
不是直接的,但是你可以将你的 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
部分是任何一种 data/type 可能有点奇怪,所以我会考虑将这部分重新命名为 value
- 但那只是我
遗憾的是,{ 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 }
第一种方法是通用的,returns 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