1

我有一些我真的想摆脱的代码重复 -

// 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)

如您所见,它是相同的算法重复 3 次。但是,我不知道如何概括需要传递像match expr with | destructureFn a -> Some a | _ -> None. 有人可以帮忙吗?实际上,我的代码中有 5 次重复(并且还在增长)需要分解。

干杯!

* 结论 *

使用 desco 的答案,我已经达到了这个重构 -

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

谢谢德斯科!

4

2 回答 2

2

在没有看到实际代码的情况下推理非常复杂,可能这样的事情会起作用

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)
于 2011-12-13T19:18:28.600 回答
1

我可能错了,但optValues

let optValues = List.map exprToOptValue exprs

似乎没有必要。它将返回Expr optionstring option或者bool option在每种情况下,这使得它更难使用。您可以保留exprs并返回它以便稍后进行一些计算:

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

或仅返回values。在后一种情况下,exprsToSomething函数的含义完全符合它们的名称:

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
于 2011-12-13T21:30:07.767 回答