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 asvar
in C # - to declare a variable;|>
— (piping) F#, ;- F# ,
SomeType<T>
SomeType<'a>
.
. , , , . , .
F# ( ) C#, ( ) . , , .
- Array<T>
! F# C#. :
F#
[|element|]
,[]
— F#.
F# , :
[|elementA;elementB|]
.
F# :
let myArray = [|1;2;3|] myArray.[1] // 2
F# 4-
Array2<'a>
,Array3<'a>
Array4<'a>
.
- List<T>
F# List<T>
C#.
:
F#
[element]
.
, , :
[elementA;elementB]
F# — ,
::
:
let myList = [1;2;3] 4 :: myList // [4;1;2;3]
,
@
:
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,2);(3,4)] |> Map.ofList // [1] = 2, [3] = 4
, , :
[(1,2);(1,3)] |> Map.ofList |> Map.find 1 = 3 // true
: :
[(1,2);(3,4)] |> Map.ofList |> Map.toList // [(1,2);(3,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#-:
F#
Async<'t>
,Task<T>
C#.
- , F# ,
Async<unit>
Task
, .
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
}
,
let!
Async- Async- — , C#await
,Task
.
, , , 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
?
- . , , , .
-
Option.bind
— :Some
— , —None
. 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>]
.