Pregunta

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!

¿Fue útil?

Solución

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)

Otros consejos

I may be wrong but optValues in

let optValues = List.map exprToOptValue exprs

seems to be unnecessary. It will return Expr option, string option or bool option in each case, which makes it more difficult to use. Either you keep exprs and return it to do some calculation later:

let exprsToValues exprToOptValue exprs =
    let values = List.choose exprToOptValue exprs
    (exprs, values)

or simply returns values only. In the latter case, meanings of exprsToSomething functions totally fit to their names:

let exprsToViolationStrs exprs = List.choose (function | Violation v -> Some v | _ -> None) exprs
let exprsToBools exprs = List.choose (function | Boolean b -> Some b | _ -> None) exprs
let exprsToStrs exprs = List.choose (function | String s -> Some s | _ -> None) exprs
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top