Getting rid of the “pyramid of doom” in F#

别来无恙 提交于 2019-12-29 08:32:08

问题


I have several verbal expressions that I've packaged into one function:

open FsVerbalExpressions
open FsVerbalExpressions.VerbalExpression
open System.Text.RegularExpressions
open System

let createOrVerbExFromList (verbExList: VerbEx list) = 
    let orVerbEx = 
        verbExList
        |> List.reduce (fun acc thing -> verbExOrVerbEx RegexOptions.IgnoreCase acc thing) //simpleVerbEx

    orVerbEx 

let k12VerbEx =     
    let kTo12 =  ["SCHOOL"; "DIST"; "SD"; "HS"; "BD OF ED"]
    kTo12
    |> List.map (fun word -> VerbEx(word))
    |> createOrVerbExFromList

let twoYearCollegeVerbEx = 
    VerbEx("2 Year College")

let universityVerbEx = 
    VerbEx("UNIV")

let privateSchoolVerbEx = 
    VerbEx("ACAD")

//Here there be dragons:
let newInst (x: string) =
    match (isMatch x k12VerbEx) with 
    | true -> "K - 12"
    | _ -> match (isMatch x twoYearCollegeVerbEx) with
            | true -> "2 Year College"
            | _ -> match (isMatch x universityVerbEx) with
                    | true -> "University" 
                    | _ -> match (isMatch x privateSchoolVerbEx) with
                            | true -> "Private / Charter School"
                            | _ -> "Other"

I'd like to rewrite the newInst function so that it's no longer the "pyramid of doom. My question is how can I get rid of the pyramid of doom? Can I get rid of it? I have the suspicion that it will be some sort of async workflow or other computational expression, but those are all very new to me.


回答1:


If you are only matching against booleans, then if ... elif is sufficient:

let newInst (x: string) =
    if isMatch x k12VerbEx then
        "K - 12"
    elif isMatch x twoYearCollegeVerbEx then
        "2 Year College"
    elif isMatch x universityVerbEx then
        "University"
    elif isMatch x privateSchoolVerbEx then
        "Private / Charter School"
    else
        "Other"

A more flexible possibility would be to create an active pattern:

let (|IsMatch|_|) f x =
    if isMatch x f then Some () else None

let newInst (x: string) =
    match x with
    | IsMatch k12VerbEx -> "K - 12"
    | IsMatch twoYearCollegeVerbEx -> "2 Year College"
    | IsMatch universityVerbEx -> "University"
    | IsMatch privateSchoolVerbEx -> "Private / Charter School"
    | _ -> "Other"



回答2:


When there is sequential repetition of exactly the same form of code, I prefer to use a data-driven approach instead:

let verbExStrings =
    [
        (k12VerbEx, "K - 12")
        (twoYearCollegeVerbEx, "2 Year College")
        (universityVerbEx, "University")
        (privateSchoolVerbEx, "Private / Charter School")
    ]

let newInst x =
    verbExStrings
    |> List.tryPick (fun (verbEx, string) -> if isMatch x verbEx then Some string else None)
    |> function Some x -> x | _ -> "Other"

An advantage of this approach is that the raw data (verbExStrings) can come in handy in other places and is not tied to your code implementation.



来源:https://stackoverflow.com/questions/39858643/getting-rid-of-the-pyramid-of-doom-in-f

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!