Generalize Similar Functions

Hey there,

I have a lot of functions that are very similar:

    let addCustomer customerNumber firstName data =
        let customer = Customer.create customerNumber firstName
        { data with Customers = data.Customers @ [ customer ] }

    let addOrder orderNumber name data =
        let order = Order.create orderNumber name
        { data with Orders = data.Orders @ [ order ] }
    
    let addInvoice id amount name data =
        let invoice = Invoice.create id amount name
        { data with Invoices = data.Invoices @ [ invoice ] }

I feel like there should be a way to extract the common behavior, but I am struggling to find a way.

Any ideas?

Thx

All functions as different as an apple and an orange. Outside similar, but inside no.

Yeah I don’t think there’s a lot of opportunity. If you wrote setters for each field of your data record like

module Data = 
  let updateCustomers fn x = { x with Customers = fn x.Customers }
  let updateOrders fn x = { x with Orders = fn x.Orders }
  ...

then you could kinda shorten it with

let snoc x xs = xs @ [x]

let addCustomer customerNumber firstName = Data.updateCustomers (snoc (Customer.create customerNumber firstName))
let addOrder orderNumber name = Data.updateOrders (snoc (Order.create orderNumber name))
let addInvoice id amount name = Data.updateInvoices (snoc (Invoice.create id amount name))

which cuts a little bit of boilerplate I guess? You could slightly update that to use lenses from F#+:

module Data = 
  let _customers f d = f d.Customers <&> fun x -> { d with Customers = x }
  let _orders f d = f d.Orders <&> fun x -> { d with Orders = x }

...

let snoc x xs = xs @ [x]

let addCustomer customerNumber firstName = over Data._customers (snoc (Customer.create customerNumber firstName))
let addOrder orderNumber name = over Data._orders (snoc (Order.create orderNumber name))
let addInvoice id amount name = over Data._invoices (snoc (Invoice.create id amount name))

which is at least a bit more standardized of a pattern than the first one, though requires anyone working with it to have a basic familiarity with lenses.

I can’t think of any other ways to shorten it.

Thank you for taking the time to provide some ideas.