Логика ветвления F # с сопоставлением с образцом - PullRequest
2 голосов
/ 21 мая 2019

Пусть у меня есть такой код на C #. Как переписать в стиле функции эту бранч-логику с помощью F #? Что я должен использовать сопоставление с образцом? активное сопоставление с образцом? дискриминационные союзы?

public class DataBase
{
    public List<string> GetEmployees(string id, string email)
    {
        if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(email))
        {
            return GetByIdAndEmail(id, email);
        }
        else if (!string.IsNullOrEmpty(email))
        {
            return GetByEmail(email);
        }
        else if (!string.IsNullOrEmpty(id))
        {
            return GetById(id);
        }
        else
        {
            return new List<string>();
        }
    }

    private List<string> GetByIdAndEmail(string id, string email)
    {
        // request something in db
        return new List<string>() { "First" };
    }

    private List<string> GetByEmail(string email)
    {
        //request something in db
        return new List<string>() { "Second" };
    }

    private List<string> GetById(string id)
    {
        // request something in db
        return new List<string>() { "Third" };
    }
}

class Program
{
    static void Main(string[] args)
    {
        DataBase DB = new DataBase();
        string id = null;
        string email = null;
        DB.GetEmployees(id, email);
    }
}

F #

let GetEmployees (id:string)(email:string) = 
    match (id,email) with
    ...

Ответы [ 2 ]

6 голосов
/ 21 мая 2019

Я думаю, что этого достаточно:

let getByIdAndEmail id email = ["First"]
let getByEmail email = ["Second"]
let getById id = ["Third"]

let getEmployees id email = 
    match String.IsNullOrEmpty id, String.IsNullOrEmpty email with
    | false, false -> getByIdAndEmail id email 
    | true, false  -> getByEmail email
    | false, true  -> getById id
    | _ -> []

Если вы хотите использовать мощь системы типов F # и ее краткий синтаксис, я предлагаю пойти дальше, написав новый строковый тип, в котором его содержимоегарантированно не будет нулевым или пустым.Так что каждый будет чувствовать себя в безопасности при использовании значений этого типа.

type ReallyString = private ReallyString of string with
    static member Create s = match String.IsNullOrEmpty s with
                             | true -> None
                             | false -> Some (ReallyString s)
    member this.Value = let (ReallyString s) = this in s

let getByIdAndEmail (id : ReallyString) (email : ReallyString) =
    // Yay, I feel safe because the id and email really have content
    // I can use id.Value and email.Value without any worry
    ["First"]
let getByEmail (email : ReallyString) =
    // Yay, I feel safe because the email really has content
    // I can use email.Value without any worry
    ["Second"]
let getById (id : ReallyString) =
    // Yay, I feel safe because the id really has content
    // I can use id.Value without any worry
    ["Third"]

let getEmployees id email =
    // I feel unsafe here, so I have to check
    // Actually I'm being forced to check because if I don't check
    // I won't have valid values to pass to the getByXXX functions above
    match ReallyString.Create id, ReallyString.Create email with
    | Some reallyId, Some reallyEmail -> getByIdAndEmail reallyId reallyEmail
    | Some reallyId, None -> getById reallyId
    | None, Some reallyEmail -> getByEmail reallyEmail
    | _ -> []
1 голос
/ 22 мая 2019

Рефакторинг в ответе Nghia Buis можно продолжить, используя активные шаблоны и различающие союзы.

open System.Text.RegularExpressions
let (|EmployeeId|_|) s = 
    match System.Int32.TryParse(s) with   // assuming your id:s are integers
    | (true,int) -> Some(int)
    | _ -> None

let (|Email|_|) s =
    let matches = Regex.Matches(s, ".*?@.*" )
    if matches.Count > 0 then Some matches.[0].Value else None

type IdString = private IdString of string with
    static member Create = 
        function
        | EmployeeId s -> Some s
        | _ -> None
    member this.Value = let (IdString s) = this in s

type Email = private Email of string with
    static member Create = 
        function
        | Email s -> Some s
        | _ -> None
    member this.Value = let (Email s) = this in s

let getByIdAndEmail (id : EmployeeId) (email : Email) =
    // Yay, I know that id and email are valid, non empty and not null
    ["First"]

let getByEmail (email : Email) =
    // email is an email adress, and not any string
    ["Second"]
let getById (id : EmployeeId) =
    // id is really an employeeId.
    ["Third"]

let getEmployees id email =
    // I feel unsafe here, so I have to check
    // Actually I'm being forced to check because if I don't check
    // I won't have valid values to pass to the getByXXX functions above
    match EmployeeId.Create id, Email.Create email with
    | Some reallyId, Some reallyEmail -> getByIdAndEmail reallyId reallyEmail
    | Some reallyId, None -> getById reallyId
    | None, Some reallyEmail -> getByEmail reallyEmail
    | _ -> []

Вы также можете явно указать в коде способ идентификации сотрудника.

type EmployeeIdentification =  //Let's state explicitly how employees may be identified
    | ById of EmployeeId
    | ByEmail of Email
    | ByIdAndEmail of EmployeeId * Email
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...