Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refactor to avoid F# Lint's warning?

Tags:

f#

I have the following nested Seq.map() calls in a function that compiles and works effectively:

|> Seq.map (fun (tradedOnKey : DateTime, portfolioSeq : seq<PortfolioId * seq<PortfolioFundRecord>>) ->
        let pricedPortfoliosGroup = 
            portfolioSeq 
            |> Seq.map (fun (p : PortfolioId, spsf : (seq<PortfolioFundRecord>)) ->
                let price = 
                    spsf 
                    |> Seq.map (fun (pfr : PortfolioFundRecord) -> pfr.Fund.ClosingPrice * float pfr.PortfolioWeight / 100.0) 
                    |> Seq.reduce (+)
                let topPortfolioFundRecord = spsf |> Seq.head
                { PortfolioId = p; Price = price; TradedOn = topPortfolioFundRecord.Fund.TradedOn }
            )
        (tradedOnKey, pricedPortfoliosGroup)
)

which prompts the following lint warning:

Lint: Seq.map f (Seq.map g x) might be able to be refactored into Seq.map (g >>f) x.

I believe the warning is prompted by these top 2 map calls:

|> Seq.map (fun (tradedOnKey : DateTime, portfolioSeq : seq<PortfolioId * seq<PortfolioFundRecord>>) ->
        let pricedPortfoliosGroup = 
            portfolioSeq 
            |> Seq.map (fun (p : PortfolioId, spsf : (seq<PortfolioFundRecord>)) ->

but I don't know how to refactor them since my 2nd parameter is a sequence and I want to "transform it" but not flatten it.

Can you suggest a way to do that? I also looked for a way to turn off the lint warning just for that code fragment but the power tools do not seem to offer a way to do that.

Here's the whole function for completeness sake:

let getPortfoliosPrices(dbFundsWithPortfolioFunds : (DbFunds * DbPortfolioFunds) Linq.IQueryable)(takenDays: int) =

let portfolioPrices =
    dbFundsWithPortfolioFunds
    |> Seq.collect(fun (f : DbFunds, fp : DbPortfolioFunds) -> 
        takenDays |> getStockPrices f.Symbol
        |> Seq.map(fun(quote : FundQuote) -> 
            let portfolioFundRec = {PortfolioId = fp.PortfolioId; PortfolioWeight = fp.Weight; Fund = quote}
            portfolioFundRec)
        )
        |> Seq.groupBy(fun (portfolioFundRec : PortfolioFundRecord) -> portfolioFundRec.Fund.TradedOn)
        |> Seq.map(fun (tradedOnKey : DateTime, spfr : PortfolioFundRecord seq) -> 
        let gpfr = spfr |> Seq.groupBy (fun(pfr : PortfolioFundRecord)->pfr.PortfolioId)
        (tradedOnKey, gpfr)
    )
    |> Seq.map (fun (tradedOnKey : DateTime, portfolioSeq : seq<PortfolioId * seq<PortfolioFundRecord>>) ->
            let pricedPortfoliosGroup = 
                portfolioSeq 
                |> Seq.map (fun (p : PortfolioId, spsf : (seq<PortfolioFundRecord>)) ->
                    let price = 
                        spsf 
                        |> Seq.map (fun (pfr : PortfolioFundRecord) -> pfr.Fund.ClosingPrice * float pfr.PortfolioWeight / 100.0) 
                        |> Seq.reduce (+)
                    let topPortfolioFundRecord = spsf |> Seq.head
                    { PortfolioId = p; Price = price; TradedOn = topPortfolioFundRecord.Fund.TradedOn }
                )
            (tradedOnKey, pricedPortfoliosGroup)
    )
portfolioPrices
like image 974
Mario Avatar asked Feb 15 '17 11:02

Mario


1 Answers

In your second top-level Seq.map, you are just passing tradedOnKey through, and do something with your sequence. You could merge all that into one, by doing:

dbFundsWithPortfolioFunds
|> Seq.collect(fun (f : DbFunds, fp : DbPortfolioFunds) -> 
    takenDays |> getStockPrices f.Symbol
    |> Seq.map(fun(quote : FundQuote) -> 
        let portfolioFundRec = {PortfolioId = fp.PortfolioId; PortfolioWeight = fp.Weight; Fund = quote}
        portfolioFundRec)
    )
    |> Seq.groupBy(fun portfolioFundRec-> portfolioFundRec.Fund.TradedOn)
    |> Seq.map(fun (tradedOnKey, spfr) -> 
        let gpfr = spfr |> Seq.groupBy (fun pfr -> pfr.PortfolioId)
        let pricedPortfoliosGroup = 
            gpfr
            |> Seq.map (fun (p, spsf) ->
                let price = 
                    spsf 
                    |> Seq.sumBy (fun pfr -> pfr.Fund.ClosingPrice * float pfr.PortfolioWeight / 100.0) 
                let topPortfolioFundRecord = spsf |> Seq.head
                { PortfolioId = p; Price = price; TradedOn = topPortfolioFundRecord.Fund.TradedOn }
            )
        (tradedOnKey, pricedPortfoliosGroup)
)

This should get rid of the warning (difficult to verify because I don't have all the type definitions for a full repro).

like image 178
Anton Schwaighofer Avatar answered Oct 09 '22 23:10

Anton Schwaighofer