Record transformation

Viewed 75

Suppose I have the following type:

type Temp<'b,'c> =
   {
      A : string
      B : 'b
      C : 'c
      D : string
   }

And I want to create a function that receives Temp<string,string> and outputs Temp<int,int>. I tried two approaches. The most cumbersome (f1) works and the most logical (in my view) does not (f2).

let f1 (r : Temp<string,string>) = //works
    {
       A = r.A
       B = r.B |> int
       C = r.C |> int
       D = r.D
    }

//doesn't work
let f2 (r : Temp<string,string>) = {r with B = r.B |> int; C = r.C |> int}

Is there another way to construct such a function without having to repeat all the fields in the body?

2 Answers

As mentioned before, you can not (ATM) use the f2 approach but you can simply create a generic version of your f1 approach and use it.

type Temp<'b,'c> = {
    A: string
    B: 'b
    C: 'c
    D: string
}

module Temp =
    let bind fB fC temp =
        {
            A = temp.A
            B = fB temp.B
            C = fC temp.C
            D = temp.D
        }

    let bind1 f = bind f f

let sTemp: Temp<string, string> = {
    A = "a"
    B = "b"
    C = "c"
    D = "d"
}

let iTemp: Temp<int, int> = sTemp |> Temp.bind int int   // with two separate functions for each generic field

let iTemp: Temp<int, int> = sTemp |> Temp.bind1 int      // with one function for both fields at once

I don't think so. A copy and update record expression can only be used to create a new record of the same type, but Temp<string, string> and Temp<int, int> are not the same type. I think there are a number of suggestions to broaden this along the lines you suggest in the F# language issue tracker (e.g. this one), but AFAIK, none have made it into the language yet.

Related