I have some code repetition that I really want to get rid of -
// here's some lib code the repetitive code relies on...
module Option
let definitize opts = List.choose id opts
// here's the start of another file...
module Ast
type Expr =
| Violation of Expr
| Boolean of bool
| String of string
// here's the repetitive code...
let exprToOptViolation expr = match expr with | Violation v -> Some v | _ -> None
let exprToOptBoolean expr = match expr with | Boolean b -> Some b | _ -> None
let exprToOptStr expr = match expr with | String n -> Some n | _ -> None
let exprsToOptViolationStrs exprs = List.map exprToOptViolation exprs
let exprsToOptBools exprs = List.map exprToOptBoolean exprs
let exprsToOptStrs exprs = List.map exprToOptStr exprs
let exprsToViolationStrs exprs =
let optViolationStrs = exprsToOptViolationStrs exprs
let violationStrs = Option.definitize optViolationStrs
(optViolationStrs, violationStrs)
let exprsToBools exprs =
let optBools = exprsToOptBools exprs
let bools = Option.definitize optBools
(optBools, bools)
let exprsToStrs exprs =
let optStrs = exprsToOptStrs exprs
let strs = Option.definitize optStrs
(optStrs, strs)
As you can see, it is the same algorithm repeated 3 times. However, I don't know how to generalize code that requires passing a destructuring facility like match expr with | destructureFn a -> Some a | _ -> None
. Can someone help? I've actually got 5 repetitions in my code (and growing) that need to get factored down.
Cheers!
* CONCLUSION *
Using desco's answer, I've reached this refactoring -
let exprsToValues exprToOptValue exprs =
let optValues = List.map exprToOptValue exprs
let values = Option.definitize optValues
(optValues, values)
let exprsToViolationStrs exprs = exprsToValues (fun expr -> match expr with | Violation v -> Some v | _ -> None) exprs
let exprsToBools exprs = exprsToValues (fun expr -> match expr with | Boolean b -> Some b | _ -> None) exprs
let exprsToStrs exprs = exprsToValues (fun expr -> match expr with | String s -> Some s | _ -> None) exprs
Thanks desco!
it is pretty complicated to reason without seeing actual code, probably something like this will work
type E = | Violation of string | Boolean of bool | String of string
module Option =
let definitize vOpt = vOpt |> List.map (function Some x -> sprintf "%A" x | _ -> "none")
let mkEToViolationsStr f exprs =
let optViolationStrs = List.map f exprs
let violationStrs = Option.definitize optViolationStrs
(optViolationStrs, violationStrs)
let exprsToViolationStrs2 = mkEToViolationsStr (function Violation v -> Some v | _ -> None)
let exprsToBools2 = mkEToViolationsStr (function Boolean b -> Some b | _ -> None)
let exprsToStrs2 = mkEToViolationsStr (function String s -> Some s | _ -> None)