NicoJuicy
NicoJuicy

Reputation: 3528

best practise to convert c# logic to f#

So i have this as a script:

#r @"..\packages\FSharp.Data.2.4.2\lib\net45\FSharp.Data.dll"
#r "System.Xml.Linq.dll"

open FSharp.Data

// provide some URL, file path, or raw JSON sample
// that can be used at compile time to generate types
type Json = JsonProvider<"example.json">

// at runtime, load up new sample matching that schema
let response = Http.Request("https://world.openfoodfacts.org/api/v0/product/737628064502.json")
let samples = Json.Parse(response.Body.ToString())

What i want to do is this:

Which in c# would be something like this:

public static Models.Product UpdateFromRemote(this Models.Product Product, string Language, string Barcode)
{
    //the f# code included above to fetch the remote source
    //only the url is fetched from:
    //  string.Format("https://{0}.openfoodfacts.org/api/v0/product/{1}.json",Language,Barcode);  

    Product.Title =  samples.Product.GenericName; //samples is the fetched resource from the f# code

    return Product;
}

What would be the logic in f#?

Currently i have this ( which is not correct/complete yet)

namespace LookupByBarcode.openfoodfacts.fSharp

open FSharp.Data

type model(Language,Barcode) = 
    member this.Language = Language
    member this.Barcode = Barcode

module getRemote = 
    type json = JsonProvider<"example.json">
        let response = json.Load("https://world.openfoodfacts.org/api/v0/product/737628064502.json")
            let Title = response.Product.ProductNameEn

Upvotes: 0

Views: 103

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243061

If you have an external DLL that you cannot modify that defines a type Product, then there is no easy way of adding new fields to the product. I think the most elegant F# way of doing this would be to wrap it in a record that adds the additional information:

type MyProduct = 
  { Product : Product
    Language : string
    Barcode : string }

Next, if you want to update a MyProduct value so that it reflects a newly obtained title, then it depends on what the underlying Product type looks like. Is it mutable or immutable?

To get idiomatic F# code, you would want to create a function that returns a clone. This is easy to do with F# records, but might be hard with C# objects. It might look something like this:

let updateProduct newTitle newLanguage myproduct =
  // Create a new `Product` with changed title. If you want to avoid mutation,
  // you need to create a new instance, which might be tedious for C# objects
  let op = myproduct.Product
  let np = 
    Product
      (Title = newTitle, OtherThing = op.OtherThing,
       YetAnotherThing = op.YetAnotherThing)

  // Now create a new updated F# record - this is much easier
  { myprodcut with Product = np; Language = newLanguage }

Working idiomatically with C# mutable objects in F# will be tricky, so my recommendation would be to define the domain model in F#, which will let you use the nice F# with keyword everywhere. That said, it might also make sense to just mutate the C# object - if that's what you really want to do.

Upvotes: 3

Related Questions