3
\$\begingroup\$

I've been wanting to try out F# for some real world programming so I decided to try rewriting a program that is being used at work.

It can be reduced to a few steps:

  1. Get report templates. In this step I query a DB and get some templates for reports
  2. Update data that the reports are working on. In this step I query some banking services and save our data on our DB
  3. Generate new reports. In this step I call a stored procedure that generates a new report

I'm trying to do this outside in and have been using Mark Seemann's blog and Scott Wlaschin's guide as a guide and this is what I've got so far:

module Helpers =
let getValuesInListOfOptions list =
 List.choose (fun x -> 
 match x with
 | Some value -> Some value
 | _ -> None ) list
module PaymentVelocityReports =
open System;
open Helpers;
type ReportTemplateName = string
type ReportTemplate = { 
 Id: int
 GroupId: int
 ReportOwnerSSN: string
 Name: ReportTemplateName
 Description: string
 Enabled: bool
 DayOfMonthToRun: int
 DateFrom: DateTime
 DateTo: DateTime option
 UpdateData: bool}
type Claimant = {
 Id: decimal
 Ssn: string
}
type BankingService = {
 Id: decimal
 ClaimantId: decimal
 Bank: string
 Username: string
 Password: string
 Enabled: bool
}
type ClaimantTemplates ={
 ReportTemplates: ReportTemplate list
 Claimant: Claimant
 BankingServices: BankingService list
}
let updateClaimantData saveNewGiros saveNewPayments (dateFrom: DateTime) (dateTo: DateTime) (bankingServices: BankingService list) = 
 List.iter (fun x -> saveNewGiros dateFrom dateTo x) bankingServices
 List.iter (fun x -> saveNewPayments dateFrom dateTo x) bankingServices
let updateData updateClaimantData (claimantTemplates: ClaimantTemplates) : ReportTemplateName list =
 if List.exists (fun x -> x.UpdateData) claimantTemplates.ReportTemplates then
 let minDate = List.map (fun x -> x.DateFrom) claimantTemplates.ReportTemplates |> List.min
 let maxDateWithNone = List.map (fun x -> x.DateTo) claimantTemplates.ReportTemplates |> List.max
 let maxDateWithoutNone = List.map (fun x -> x.DateTo) claimantTemplates.ReportTemplates |> getValuesInListOfOptions |> List.max
 match maxDateWithNone with
 | None -> updateClaimantData minDate DateTime.Today claimantTemplates.BankingServices
 | _ -> updateClaimantData minDate maxDateWithoutNone claimantTemplates.BankingServices
 List.map (fun x -> x.Name) claimantTemplates.ReportTemplates
let getClaimantTemplates data createClaimantTemplate : ClaimantTemplates list = 
 data |> List.map createClaimantTemplate
//The root of the program
let generateReports (getClaimantTemplates: unit -> ClaimantTemplates list) (updateData: ClaimantTemplates -> ReportTemplateName list) (createReport: ReportTemplateName -> unit) =
 getClaimantTemplates () |> List.map updateData |> List.concat |> List.map createReport |> ignore

I'm at the point where the updateClaimantData and getClaimantTemplates require data access and the createReport function that generateReports needs is also a data access function.

I was hoping to get some criticism to see if I'm on the right track. I'm both new to the language and functional languages as well.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Oct 14, 2015 at 16:26
\$\endgroup\$
1
  • \$\begingroup\$ The desire to improve code is implied for all questions on this site. Question titles should reflect the purpose of the code, not how you wish to have it reworked. See How to Ask. \$\endgroup\$ Commented Oct 14, 2015 at 17:01

1 Answer 1

2
\$\begingroup\$

From a cursory glance, this looks like a good start, but I haven't made a full exegesis of the code.

A couple of observations:

The getValuesInListOfOptions function seems redundant. AFAICT, you can rewrite the function as List.choose id list, in which case you could inline that expression and remove the function.

It seems odd to me that the function with the comment The root of the program is still a higher-order function defined in the same module as all the other functions. I'd expect the root of the program to be something akin to a main function, that only takes command-line string arguments as input, if it takes any arguments at all.

answered Oct 14, 2015 at 19:15
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the input Mark. It's good to know I'm on the right track. The comment was just to make it clear that where the outermost function of the module was. It will be called from a main function and the other functions composed there as well. \$\endgroup\$ Commented Oct 15, 2015 at 9:35

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.