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 comovar
en C # - para declarar una 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>]
.