Préface
Ma transition vers F # comme langue préférée était un peu semée d'embûches. Après une dizaine d'années d'utilisation quasi constante de C #, ma curiosité s'est éveillée lorsque j'ai entendu parler de cet autre # langage. Ma première réaction a été celle que j'ai vue d'autres développeurs C # depuis lors - le déni - C # est un bon langage et je suis à l'aise avec lui, alors pourquoi gaspiller votre énergie à apprendre autre chose? Mais la curiosité est restée - et au moins quelques fois mettre de côté la soirée pour lire un article d'introduction de base et essayer d'écrire des kata en fa #. Cela n'a pas collé, car je me sentais juste perdu et je ne pouvais pas traduire mon expérience d'utilisation de C # en un confort même distant avec F #. Il est assez facile d'omettre les accolades, d'hésiter un peu pour ne pas oublier let
au lieu de var
- mais commentfaire ce que je voulais?
Je ne m'en suis pas rendu compte à l'époque, mais je pense avoir vu une faille potentielle dans la façon dont les développeurs F # parlent, décrivent et présentent leur langage au monde extérieur. Il existe une base complète de matériaux sur toutes les fonctionnalités et fonctionnalités de F #: types de données algébriques, correspondance exhaustive, inférence de type, etc. Il existe de nombreux articles sur la façon de résoudre une grande variété de problèmes avec F #. Mais il me semble qu'il manque quelque chose comme ce qui suit: des instructions sur la façon de prendre ce avec quoi vous êtes à l'aise en C # et de les traduire en F #. Je me demande donc si nous pouvons en quelque sorte combler cette faille.
Dans le même temps, peu est exigé du lecteur - une connaissance superficielle des trois principaux points de la syntaxe F #:
let
utilisé commevar
en C # - pour déclarer une 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>]
.