Generics in a notation with syntax

If I have an entry with a generic field, is there a way to mimic the convenient syntax with

when changing the generic?

i.e. if I have

type User<'photo> = // 'photo can be Bitmap or Url
  { first: string; last: string; address: string; phone: string; photo: 'photo }

      

I want to write something like

let loadUser(user: User<Url>): User<Bitmap> =
  { user with
    photo = download user.photo }

      

But it looks like I should write this instead.

let loadUser(user: User<Url>): User<Bitmap> =
  { first = user.first
    last = user.last
    address = user.address
    phone = user.phone
    photo = download user.photo }

      

Is there a way to get the first syntax?

+3


source to share


2 answers


not directly, but you can make your User

functor (for the part 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 }

      

once and write (for example):



let loadUser (user : User<Url>) : User<Bitmap> =
    fmap download user

      

also you can rename fmap

to withPhoto

if you prefer let loadUser = withPhoto download

: D

now it might be a little weird that the part photo

is any datatype / type, so I would consider renaming this part to only value

, but that's just me

+5


source


Unfortunately, the syntax { with .. }

does not handle the case where the type changes (although I think this could be added, so feel free to open the suggestion to the F # user voice page!)

Added a function map

, but another alternative is to define a method With

for the type. This can take optional parameters for non-general fields. For a generic field, you cannot do this (because it will unify types), but you can have an overload:

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 }

      



The first method is generic and returns User

with a different type of photo. The second method does not change the photo and therefore is not common. Then you can use it like this:

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

      

+4


source







All Articles