I have an algorithm that looks up data based on what the user inputs. There are multiple ways to specify a unique record so I am allowing the user to input several different unique identifiers. When I begin writing the algorithm however, alarm bells go on in my head because it seems verbose or non-functional. It just feels like I'm doing something wrong. Let me show you in code.
// Types for the domain model
type EmployeeID = ID of int
type EmployeeName =
{ First : string
Last : string }
// Some instances of EmployeeName to use later
let james = {First = "James"; Last = "Winklenaught"}
let ted = {First = "Theodore"; Last = "Chesterton"}
// Input for the algorithm
type matcherInput =
| EmployeeIDWrapper of EmployeeID
| EmployeeNameWrapper of EmployeeName
// Output of the algorithm
type matcherOutput =
{ Info : string }
// Returns data if it found it from our search algorithm
let LookupEmployee (input : matcherInput) : matcherOutput option =
(*
There's a lot of algorithm here in the real version
that creates the lookup tables (maps). I just put in
some dummy data instead.
*)
let numberLookup =
Map.ofList [(james, ID 1); (ted, ID 2)]
let infoLookup =
Map.ofList [(ID 1,{Info = "CEO"});(ID 2,{Info = "CFO"})]
// output
match input with
| EmployeeIDWrapper number ->
Map.tryFind number infoLookup
| EmployeeNameWrapper name ->
Map.tryFind name numberLookup
|> Option.bind (fun number -> Map.tryFind number infoLookup)
// doesn't work = (
LookupEmployee james
LookupEmployee (ID 1)
// right, but verbose
LookupEmployee (EmployeeNameWrapper james)
LookupEmployee (EmployeeIDWrapper (ID 1))
Somehow the needing to unwrap everything seems excessive to me. Should I not be using the discriminated union in this case? Is there an established functional design pattern I could leverage?
Aucun commentaire:
Enregistrer un commentaire