Az F# programozási nyelv

Imperatív programozás

A unit típus

Az F# nyelvben minden kifejezés egy értékben kell végződjön. Azok a kifejezések amik nem adnak vissza érdemleges értéket, unit típusúak.
A unit típus más nyelvek(C#, C++) void típusára emlékeztet leginkább. Csak () értéke lehet, ami inkább egy kitöltő, mikor más érték nem generálódik vagy nem szükséges. Gyakran használják mikor a nyelv szintaxisa megkövetel valahol egy értéket, viszont a program szempontjából ez szükségtelen.

Néhány konstrukció kifejezetten unit típust vár el. Például egy do kötés vagy minden, legfelsőbb szintű kötés ilyen.
A fordító figyelmeztetést dob ha ezek bármelyike nem unit típusú értéket eredményez és ezt az értéket nem használja fel semmi.

let function1 x y = x + y // A következő sor fordítói figyelmeztetést eredményez. function1 10 20 // A következő változtatások bármelyike megszünteti ezt. // Ezt használjuk, ha visszatérési értéket várunk. let result = function1 10 20 // Ezt használjuk ha nincs szükségünk a visszatérési értékre. function1 10 20 |> ignore

A mutable kulcsszó

Alapvetően immutable adattagokat hozhatunk létre a let kulcsszóval. Lehetőségünk van a mutable kulcsszó segítségével a későbbiekben változtatható értékű adattagokat létrehozni.
Ezek értékét később a <- operátorral írhatjuk felül.

let mutable x = 1 x <- x + 1

Mutable rekord típus definiálása

A rekordok alap esetben immutable típusok. Könnyen létrehozhatunk egy más értékű rekordot másoló és felülíró kostruktorokkal, viszont ez plusz erőforrást igényel.
Ha a teljes rekordot nem is, a rekord bármelyik mezőjét mutable mezővé tehetjük, így lényegében mezőnként a teljes rekordot is.

type Car = { Make : string Model : string mutable Odometer : int } let myCar = { Make = "SMTG"; Model = "Coupe"; Odometer = 108112 } myCar.Odometer <- myCar.Odometer + 21

A Ref típus és ref operátor

A ref operátort egy érték elé téve egy új referencia cellát készíthetünk, ami magába foglalja az adott értéket. Ez az érték alap esetben mutable.
A referencia cella egy tényleges értéket tartalmaz, nem egy címet! Létrehozásakor egy mutable másolat készül az adott értékről és ez kerül a cellába.
A cellát dereferálhatjuk a !(bumm) operátorral.

// Deklaráció. let refVar = ref 6 // Változtassuk az értéket. refVar := 50 // Dereferálás. printfn "%d" !refVar //Az output 50 lesz

A referencia cellák a Ref generikus rekord típus példányai.

type Ref<'a> = { mutable contents: 'a }

Típusannotációnál a byref kulcsszóval jelezhetjük a fordítónak, hogy egy referencia cellát várunk.

type Incrementor(delta) = member this.Increment(i : int byref) = i <- i + delta let incrementor = new Incrementor(1) let mutable myDelta1 = 10 incrementor.Increment(ref myDelta1) // 10: printfn "%d" myDelta1 let mutable myDelta2 = 10 incrementor.Increment(&myDelta2) // 11: printfn "%d" myDelta2 let refInt = ref 10 incrementor.Increment(refInt) // 11: printfn "%d" !refInt

A legtöbb esetben ugyan arra a célra használható mutable változó és referencia cella is, viszont néha nem használhatunk mutable változót, ilyenkor referencia cellára van szükségünk.
Általános gyakorlat, hogy ahol lehet, ott mutable változót használjunk.
Az olyan kifejezésekben amik closure-t eredményeznek (ezeket későbbi végrehajtásra tároljuk), a fordító nem enged mutable változót használni!

// A konzolról beolvasott sorok kiiratása. let PrintLines1() = let mutable finished = false while not finished do match System.Console.ReadLine() with | null -> finished <- true | s -> printfn "line is: %s" s // Csomagoljuk az egészet egy szekvenciába a késleltetés miatt. let PrintLines2() = seq { let mutable finished = false // Fordítási hiba: while not finished do match System.Console.ReadLine() with | null -> finished <- true | s -> yield s } // Referencia cellát kell használnunk. let PrintLines3() = seq { let finished = ref false while not !finished do match System.Console.ReadLine() with | null -> finished := true | s -> yield s }