دللني F # ، أو لماذا لم أعد أرغب في الكتابة في C #

C#


, , , , . Python Javascript ( ), Java , , value-, - Integer, . — C# .


, .
, ,
, .


F#.


?


, :


  • , , .
  • -, Discriminated Unions .
  • Computation Expressions
  • SRTP ( -)
  • null, .
  • type inference

null , , Task<IEnumerable<Employee>>. .


, POCO :


public class Employee
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public bool HasAccessToSomething { get; set; }
    public bool HasAccessToSomethinElse { get; set; }
}

, , . , ?


F# :


type Employee =
{ Id: Guid
  Name: string
  Email: string
  Phone: string
  HasAccessToSomething: bool
  HasAccessToSomethingElse: bool }

. , , . C# public { get; set; }. , F# null.


, , C# , public :


public class Employee
{
    public Guid Id { get; }
    public string Name { get; }
    public string Email { get; }
    public string Phone { get; }
    public bool HasAccessToSomething { get; }
    public bool HasAccessToSomethinElse { get; }

    public Employee(Guid id, string name, string email, string phone, bool hasAccessToSmth, bool hasAccessToSmthElse)
    {
        Id = id;
        Name = name;
        Email = email;
        Phone = phone;
        HasAccessToSomething = hasAccessToSmth;
        HasAccessToSomethinElse = hasAccessToSmthElse;
    }
}

! , 3 : .
, , / , .


F# . .


:


let employee =
    { Id = Guid.NewGuid()
      Name = "Peter"
      Email = "peter@gmail.com"
      Phone = "8(800)555-35-35"
      HasAccessToSomething = true
      HasAccessToSomethinElse = false}

, . , — . , ? :


let employee2 = { employee with Name = "Valera" }

C#? , .


, { get; } — . ?


?


-. - , , true. , false. ? ? , - ? , .


— , , .
:


  • , — ,
  • ,
  • / -,

  • , , .


    C# , , .



, . ? F# :


  • Structural Equality
  • Structural Comparison

:


if employee1 = employee2 then
//...

. Equals , Object.ReferenceEquals, .


- , , , Equals & GetHashCode , . , - — , . , : , HashSet<> & SortedSet<>, ( , , ), .


Discriminated Unions


, , . , try { i = Convert.ToInt32("4"); } catch()... int.TryParse.


, . ? ValidationException. ? IndexOutOfRangeException!


, , , - . — OutOfMemoryException, StackOverflowException, AccessViolationException .. — ? ? Int32, 2 32 . , 10000. . Int32, , , , "" !
— . .


, , : , " , , , ". ( ), string ErrorMessage & bool IsSuccess. C# — , .


-,


public class Result<TResult, TError>
{
    public bool IsOk { get; set; }
    public TResult Result { get; set; }
    public TError Error { get; set; }
}

, , , . , , IsOk, , .


F# :


type Result<'TResult, 'TError> =
    | Ok of 'TResult
    | Error of 'TError

type ValidationResult<'TInput> =
    | Valid of 'TInput
    | Invalid of string list

let validateAndExecute input =
    match validate input with //    
    | Valid input -> Ok (execute input) //   -  ""  
    | Invalid of messages -> Error messages //  ,     

, , , . xml doc, - , try/catch . — , .


, . BusinessException ApiException, , , , , - , , , 404 403 500. , .


F# , match . , DU. DU , :


type UserCreationResult =
    | UserCreated of id:Guid
    | InvalidChars of errorMessage:string
    | AgreeToTermsRequired
    | EmailRequired
    | AlreadyExists

, . AgreeToTermsRequired , , .


, ( ). . , , , , .


, if/else :


let doSmth myArray index =
    match Array.tryItem index myArray with
    | Some elem -> Console.WriteLine(elem)
    | None -> ()

Option:


type Option<'T> =
    | Some of 'T
    | None

, , , , - . , .



expression-based .
:


  • — . .
  • .

( ) , .


Expression-based design , , . :


let a = if someCondition then 1 else 2

, if, else.
C# :


int a = 0;
if(someCondition)
{
    a = 1;
}
else
{
    a = 2;
}

, a , , .


, — I/O, . . - , .



: , . , , . DI , - .


, , , 2 5, , 3-5 , , . 1-2 (?) , . , . — - . , , , . , . , , — - , . - , . . . . , . , , .


: - 1 , , , . , DI , . , , , . , , . , , , .


-. — , . , , , . , , , , . , ? , !


:


let getReport queryData =
    use connection = getConnection()
    queryData
    |> DataRepository.get connection //       ,    
    //         lifestyle'    
    |> Report.build

, |> , :


let gerReport queryData =
    use connection = getConnection()
    Report.build(DataRepository.get connection queryData)

C#:


public ReportModel GetReport(QueryData queryData)
{
    using(var connection = GetConnection())
    {
        // Report  --  .    F# 
        return Report.Build(DataRepository.Get(connection, queryData));
    }
}

, :


let getReport qyertData =
    use connection = getConnection()
    queryData
    |> (DataRepository.get connection >> Report.build)

, Report.build . . , FsCheck, , , . , , - .


, — 1 . ? , , , , .


, . , . , , EntityFramework Dapper, .


Statically Resolved Type Parameters (SRTP)


, .


let inline square
     (x: ^a when ^a: (static member (*): ^a -> ^a -> ^a)) = x * x

, . , , . !


let inline GetBodyAsync x = (^a: (member GetBodyAsync: unit -> ^b) x)

open System.Threading.Tasks
type A() =
    member this.GetBodyAsync() = Task.FromResult 1

type B() =
    member this.GetBodyAsync() = async { return 2 }

A() |> GetBodyAsync |> fun x -> x.Result // 1
B() |> GetBodyAsync |> Async.RunSynchronously // 2

, , , — ! C#.


Computation Expressions


Result. , , Result. , .
,


let res arg =
    match doJob arg with
    | Error e -> Error e
    | Ok r ->
        match doJob2 r with
        | Error e -> Error e
        | Ok r -> ...


type ResultBuilder() =
    member __.Bind(x, f) =
        match x with
        | Error e -> Error e
        | Ok x -> f x
    member __.Return x = Ok x
    member __.ReturnFrom x = x

let result = ResultBuilder()

:


let res arg =
    result {
        let! r = doJob arg
        let! r2 = doJob2 r
        let! r3 = doJob3 r2
        return r3
    }

let! Error e . , Ok r3.
, . DSL.


, , — task & async. , — Async. F#, , cold start, Tasks API. , . :


let myTask =
    task {
        let! result = doSmthAsync() //    await Task
        let! result2 = doSmthElseAsync(result)
        return result2
    }

let myAsync =
    async {
        let! result = doAsync()
        let! result2 = do2Async(result)
        do! do3Async(result2)
        return result2
    }

let result2 = myAsync |> Async.RunSynchronously

let result2Task = myAsync |> Async.StartAsTask

let result2FromTask = myTask |> Async.AwaitTask


(DTO, ) , . 1 , , - .


, F# — , . by design, , . — : , - . , , , C# .


, 7 , 130 .




, . , 1 1 . C# . — , . , , , -. , — pattern matching, , nullable reference types.
, -, , F#, -, . Pattern matching Discriminated unions & Record destruction — , , . Nullable reference types — , Option .
, F# — , "" .
F# — .


, . Property-based (, FsCheck) , QA . - , - . , , , - - . F# . .

Source: https://habr.com/ru/post/ar428930/


All Articles