Избавляемся от "пирамиды гибели" в F#

У меня есть несколько словесных выражений, которые я упаковал в одну функцию:

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"

Я хотел бы переписать newInst функционировать так, чтобы это больше не "пирамида гибели". Мой вопрос: как мне избавиться от пирамиды гибели? Можно ли от нее избавиться? У меня есть подозрение, что это будет своего рода async рабочий процесс или другое вычислительное выражение, но все это очень ново для меня.

2 ответа

Решение

Если вы совпадаете только с логическими значениями, то if ... elif достаточно:

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"

Более гибкой возможностью было бы создание активного шаблона:

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"

Когда происходит последовательное повторение одного и того же вида кода, я предпочитаю использовать подход, основанный на данных:

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"

Преимущество этого подхода заключается в том, что необработанные данные (verbExStrings) может пригодиться в других местах и ​​не привязан к реализации вашего кода.

Другие вопросы по тегам