Un manual de F # para desarrolladores curiosos de C #

Prefacio



Mi transición a F # como mi idioma favorito estuvo un poco llena de obstáculos. Después de unos diez años de uso casi constante de C #, mi curiosidad se despertó cuando escuché sobre este otro # lenguaje. Mi primera reacción fue la que he visto de otros desarrolladores de C # desde entonces - negación - C # es un buen lenguaje y me siento cómodo con él, así que ¿por qué desperdiciar su energía aprendiendo algo más? Pero la curiosidad permaneció, y al menos algunas veces aparté la noche para leer una publicación introductoria básica e intentar escribir algunos kata en F #. No se mantuvo, porque me sentí perdido y no pude traducir mi experiencia de usar C # en una comodidad remota con F #. Es bastante fácil omitir las llaves, vacilar un poco para no olvidar en let



lugar de var



... pero cĂłmohacer lo que queria?







No me di cuenta en ese momento, pero creo que vi una falla potencial en la forma en que los desarrolladores de F # hablan, describen y presentan su lenguaje al mundo exterior. Existe una amplia base de materiales sobre todas las caracterĂ­sticas y funcionalidades de F #: tipos de datos algebraicos, correspondencia exhaustiva, inferencia de tipos, etc. Hay muchos artĂ­culos sobre cĂłmo resolver una amplia variedad de problemas con F #. Pero me parece que falta algo como lo siguiente: algunas instrucciones sobre cĂłmo tomar aquello con lo que se siente cĂłmodo en C # y traducirlas a F #. AsĂ­ que me pregunto si de alguna manera podemos cerrar este defecto.







Al mismo tiempo, se requiere poco del lector: un conocimiento superficial de los tres puntos principales de la sintaxis de F #:







  • let



    usado como var



    en C # - para declarar una variable;
  • |>



    — (piping) F#, ;
  • F# , SomeType<T>



    SomeType<'a>



    .


. , , , . , .

















F# ( ) C#, ( ) . , , .









- Array<T>





! F# C#. :







  1. F# [|element|]



    , []



    — F#.







  2. F# , : [|elementA;elementB|]



    .







  3. F# :







    let myArray = [|1;2;3|]
    myArray.[1] // 2
          
          





  4. F# 4- Array2<'a>



    , Array3<'a>



    Array4<'a>



    .









- List<T>





F# List<T>



C#.







:







  1. F# [element]



    .







  2. , , : [elementA;elementB]









  3. F# — , ::



    :







    let myList = [1;2;3]
    4 :: myList // [4;1;2;3]
          
          





  4. , @



    :







    let listA = [1;2]
    let listB = [3;4]
    listA @ listB // [1;2;3;4]
          
          







- Dictionary<TKey,TValue>





« , » — F# Map<'key,'value>



, C# Dictionary<TKey,TValue>



, .NET, IDictionary<TKey,TValue>



IEnumerable<T>









:







  1. , , — :







    [(1,2);(3,4)] |> Map.ofList // [1] = 2, [3] = 4
          
          





  2. , , :







    [(1,2);(1,3)] |> Map.ofList |> Map.find 1 = 3 // true
          
          





  3. : :







    [(1,2);(3,4)] |> Map.ofList |> Map.toList // [(1,2);(3,4)]
          
          





  4. Map



    F# C#, C# IDictionary



    , dict



    . , - , .







    [(1,2);(3,4)] |> dict
          
          









F# C#, , , C# , , , ; F# , . , C#- myDictionary.Add(someKey,someValue)



F# Map.add someKey someValue myMap



.







LINQ



F# , , C# LINQ, , F# , , . , , . — LINQ , — , , LINQ F#:







  • .Aggregate()



    .fold



    .reduce



    , , , ;
  • .Select()



    .map



    ;
  • .SelectMany()



    .collect



    ;
  • .Where()



    .where



    .filter



    ( , , )
  • .All()



    .forall



    ;
  • .Any()



    .exists



    , , .isEmpty



    , , - ;
  • .Distinct()



    - .distinct



    .distinctBy



    , ;
  • .GroupBy()



    - .groupBy



    ;
  • .Min()



    .Max()



    - .min



    .max



    .minBy



    .maxBy



  • .OrderBy()



    .sortBy



    , .OrderByDescending()



    .sortbyDescending



    ;
  • .Reverse()



    .rev



    ;
  • .First()



    .head



    , , .find



    , , . .FirstOrDefault()



    .tryHead



    .tryFind



    , Option, Some matchingValue



    , None



    , , , ;
  • .Single()



    .exactlyOne



    , .SingleOrDefault()



    .tryExactlyOne



    .


, .



,




  • .min



    , .minBy



    , .max



    .maxBy



    ;
  • .sum



    , .sumBy



    , .average



    , .averageBy



    ;
  • .find



    , .tryFind



    , .pick



    .tryPick



    ;
  • .head



    , .tryHead



    , .last



    .tryLast



    ;
  • .fold



    .reduce



    ;
  • .foldBack



    .reduceBack



    , .




  • .map



    ;
  • .indexed



    , : , [1]



    [(0,1)]



    ;
  • .mapi



    , ;
  • .sort



    , .sortDescending



    , .sortBy



    .sortByDescending



    .




  • .filter



    , , ;
  • .choose



    .filter



    , ;
  • .skip



    n



    ;
  • .take



    .truncate



    n



    -, , ;
  • .distinct



    .independentBy



    .




  • .collect



    .




  • .windowed



    n



    : , [1; 2; 3]



    [[1; 2]; [2; 3]]



    , n = 2



    ;
  • .groupBy



    , , — , : , [1; 2; 3]



    , (fun i -> i % 2)



    , [(0, [2]); (1, [1; 3])]



    ;
  • .chunkBySize



    , n



    : , [1; 2; 3]



    [[1; 2]; [3]]



    , n = 2



    ;
  • .splitInto



    , n



    : , [1; 2; 3]



    [[1]; [2]; [3]]



    , n = 3



    .




  • .iter



    .iteri



    , .






  • .singleton



    ;
  • .init



    .






  • .append



    , ;
  • .concat



    , ;
  • .map2



    .fold2



    .map



    .fold



    , / ;
  • .allPairs



    2 ;
  • .zip



    .zip3



    2 ( 3) , .




F# C#, , C#-:







  1. F# Async<'t>



    , Task<T>



    C#.







  2. - , F# , Async<unit>



    Task



    , .







  3. F# Task<T>



    Async.StartAsTask



    Async.AwaitTask



    .









F# C# : C# "" await



, async



; F# , computation expression



, . , :







let timesTwo i = i * 2 //       

//       

let timesTwoAsync i = async { //  ,     computation expression      ,        
   return i * 2 //      `return`   
}

let timesFour i = async {
    let! doubleOnce = timesTwoAsync i //     `!`   `let!` —    `await`  C# —     `Async<'a>`
    //  ,         `let!` —       
    let doubleTwice = timesTwo doubleOnce //           

    return doubleTwice
}
      
      





  1. , let!



    Async- Async- — , C# await



    , Task



    .







  2. , , , F# , , let!



    — , Async<'a>



    , . C# , await



    , async



    .











-, : , — F# C#. ; , F# C#, , . , null



C#. C#, :







public Foo DoSomething(Bar bar)
{
    if (bar.IsInvalid)
    {
        return null;
    }

    return new Foo(bar.Value);
}
      
      





, DoSomething



null



, . , , — LINQ FirstOrDefault()



, , IEnumerable<T>



, null



.







, F# Option<'a>



— : None



null



, , Some



? pattern matching .HasValue



— ? , F# : , , , . , , , , map



bind



, . Option



:







  • map



    : 'a -> 'b



    Option<'a>



    , Option<'b>



    ;
  • bind



    : 'a -> Option<'b>



    Option<'a>



    , Option<'a>



    .


, :







// string -> Option<string>
let getConfigVariable varName =
    Private.configFile
    |> Map.tryFind varName

// string -> Option<string[]>
let readFile filename =
    if File.Exists(filename)
        then Some File.ReadLines(filename)
        else None

// string[] -> int
let countLines textRows = Seq.length file

getConfigVariable "storageFile"                 // 1
|> Option.bind readFile                         // 2
|> Option.map countLines                        // 3
      
      





?







  1. . , , , .
  2. Option.bind



    — : Some



    — , — None



    .
  3. Option.map



    — Some



    , , .


, 3 bind



map



— , ? readFile



countLines



— bind



, flatten



(. .: , Option.flatten) Option



, . : map



, 2 Option<Option<string[]>>



— 3 Option.map (Option. map countLines)



!







, , Option



? . — . , Option



, , - , . , , , , :







  • Option.defaultValue



    'a



    Option<'a>



    — Option



    , , 'a



    , .
  • Option.defaultWith



    — , unit -> 'a



    .


, F# Result<'a,'b>



, bind



map



( mapError



, ) — None



Error



, , — string



.







C#- F



F# — , , C#- , - Haskell, — , .NET C#-, . C# ( ) F#, , :







  • C#- F# . - , - :







    "1" |> Int32.Parse                          //  Int32.Parse("1")
    ("1", NumberStyles.Integer) |> Int32.Parse  //  Int32.Parse("1", NumberStyles.Integer)
    NumberStyles.Integer |> Int32.Parse "1"     //  ,     ,     .
          
          





  • C#- — , , — F#. JSON, / Unions Records — , F#. , Newtonsoft.Json



    Newtonsoft.Json.FSharp



    , System.Text.Json



    — FSharp.SystemTextJson



    . , F# Thoth



    Chiron



    .







  • C# null



    , ( ) (. .: fsharp/fslang-suggestions#577) nullable reference type C#, C# , Option.ofNullable



    ( Nullable<T>



    ) Option.ofObj



    ( ), .







  • C#, , Action<T>



    Func<T>



    , - F# , . : unit



    void



    F# — ()



    — Action<T>



    'T -> unit



    , (fun _ -> printfn "I'm a lambda!")



    ; , Fun <T>



    unit -> 'T



    , (fun () -> 123)



    .







  • , C#- , , <>



    , F# — [Serializable]



    C# [<Serializable>]



    F#. : [<DllImport('user32.dll', CharSet = CharSet.Auto)>]



    . , , , : , [<AttributeOne; AttributeTwo>]



    .










All Articles