An F # Primer for Curious C # Developers

Foreword



My transition to F # as my favorite language was a bit littered with obstacles. After about ten years of almost constant use of C #, my curiosity aroused when I heard about this other # language. My first reaction was the one I've seen from other C # developers since then - denial - C # is a good language and I'm comfortable with it, so why waste your energy learning something else? But the curiosity remained - and at least a few times set aside the evening to read a basic introductory post and try to write some kata in F #. It didn't catch on because I just felt lost and couldn't translate my experience of using C # into even remote comfort with F #. It's easy enough to omit the curly braces, to hesitate a bit so as not to forget let



instead var



- but howdo what i wanted?







I didn't realize it at the time, but I think I saw a potential flaw in the way F # developers speak, describe, and present their language to the outside world. There is an extensive base of materials on all the features and functionality of F #: Algebraic Data Types, Exhaustive Matching, Type Inference, etc. There are many articles on how to solve a wide variety of problems with F #. But it seems to me that something like the following is missing: some directions on how to take what you are comfortable with in C # and translate it to F #. So I'm wondering if we can somehow close this flaw.







At the same time, little is required from the reader - a superficial acquaintance with the three main points of F # syntax:







  • let



    used as var



    in C # - to declare a 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