Bagikan melalui


Fungsi

Fungsi adalah unit dasar dari eksekusi program dalam bahasa pemrogram apa pun. Seperti di bahasa lain, fungsi F# memiliki nama, dapat memiliki parameter dan mengambil argumen, serta memiliki bagian isi. F# juga mendukung konstruksi pemrograman fungsional seperti memperlakukan fungsi sebagai nilai, menggunakan fungsi tanpa nama di ekspresi, komposisi fungsi untuk membentuk fungsi baru, fungsi kurir, dan definisi implisit fungsi melalui penerapan parsial argumen fungsi.

Anda menentukan fungsi menggunakan kata kunci let, atau, jika fungsinya rekursif, gunakan kombinasi kata kunci let rec.

Sintaks

// Non-recursive function definition.
let [inline] function-name parameter-list [ : return-type ] = function-body
// Recursive function definition.
let rec function-name parameter-list = recursive-function-body

Keterangan

function-name adalah pengidentifikasi yang mewakili fungsi. parameter-list terdiri dari parameter berturut-turut yang dipisahkan oleh spasi. Anda bisa menentukan jenis eksplisit untuk setiap parameter, seperti yang dijelaskan di bagian Parameter. Jika Anda tidak menentukan jenis argumen tertentu, pengompilasi mencoba akan menyimpulkan jenis dari bagian isi fungsi. function-body terdiri dari sebuah ekspresi. Ekspresi yang menjadi bagian isi fungsi biasanya merupakan ekspresi majemuk yang terdiri dari sejumlah ekspresi gabungan yang berpuncak pada ekspresi akhir yang merupakan nilai yang ditampilkan. return-type adalah titik dua yang diikuti oleh jenis dan bersifat opsional. Jika Anda tidak menentukan jenis nilai yang ditampilkan secara eksplisit, pengompilasi akan menentukan jenis yang ditampilkan dari ekspresi akhir.

Definisi fungsi sederhana terlihat seperti berikut:

let f x = x + 1

Di contoh sebelumnya, nama fungsi adalah f, argumennya adalah x, yang memiliki jenis int, bagian isi fungsi adalah x + 1, dan nilai yang ditampilkan berjenis int.

Fungsi dapat ditandai sebagai inline. Untuk informasi tentang inline, lihat Fungsi Sebaris.

Cakupan

Pada setiap tingkat cakupan selain cakupan modul, bukankah kesalahan untuk menggunakan kembali nama fungsi atau nilai. Jika Anda menggunakan kembali nama, nama yang dideklarasikan nantinya akan membayangi nama yang dideklarasikan sebelumnya. Namun, pada cakupan tingkat atas di modul, nama harus unik. Misalnya, kode berikut menghasilkan kesalahan saat muncul di cakupan modul, tetapi tidak ketika muncul di dalam fungsi:

let list1 = [ 1; 2; 3]
// Error: duplicate definition.
let list1 = []
let function1 () =
   let list1 = [1; 2; 3]
   let list1 = []
   list1

Tetapi kode berikut dapat diterima pada tingkat cakupan apa pun:

let list1 = [ 1; 2; 3]
let sumPlus x =
// OK: inner list1 hides the outer list1.
   let list1 = [1; 5; 10]
   x + List.sum list1

Parameter

Nama parameter tercantum setelah nama fungsi. Anda dapat menentukan jenis untuk parameter, seperti yang ditunjukkan pada contoh berikut:

let f (x : int) = x + 1

Jika Anda menentukan jenis, maka jenis ini mengikuti nama parameter dan dipisahkan dari nama oleh titik dua. Jika Anda menghilangkan jenis untuk parameter, jenis parameter itu disimpulkan oleh pengompilasi. Misalnya, di definisi fungsi berikut, argumen x disimpulkan berjenis int karena 1 berjenis int.

let f x = x + 1

Namun, pengompilasi akan mencoba untuk membuat fungsi se-generik mungkin. Misalnya, perhatikan kode berikut:

let f x = (x, x)

Fungsi ini membuat tuple dari satu argumen jenis apa pun. Karena jenisnya tidak ditentukan, fungsi itu dapat digunakan dengan jenis argumen apa pun. Untuk informasi selengkapnya, lihat Generalisasi Otomatis.

Bagian Isi Fungsi

Bagian isi fungsi dapat berisi definisi fungsi dan variabel lokal. Variabel dan fungsi tersebut berada dalam cakupan di bagian isi fungsi saat ini tetapi tidak di luarnya. Anda harus menggunakan indentasi untuk menunjukkan bahwa definisi berada dalam bagian isi fungsi, seperti yang ditunjukkan di contoh berikut:

let cylinderVolume radius length =
    // Define a local value pi.
    let pi = 3.14159
    length * pi * radius * radius

Untuk informasi selengkapnya, lihat Panduan Pemformatan Kode dan Sintaks Verbose.

Nilai yang Dikembalikan

Pengompilasi menggunakan ekspresi akhir dalam bagian isi fungsi untuk menentukan nilai dan jenis yang ditampilkan. Pengompilasi mungkin menyimpulkan jenis ekspresi akhir dari ekspresi sebelumnya. Di fungsi cylinderVolume, yang ditunjukkan di bagian sebelumnya, jenis pi ditentukan dari jenis harfiah 3.14159 menjadi float. Pengompilasi menggunakan jenis pi untuk menentukan jenis ekspresi length * pi * radius * radius menjadi float. Karena itu, jenis keseluruhan fungsi yang ditampilkan adalah float.

Untuk menentukan jenis yang ditampilkan secara eksplisit, tulis kode sebagai berikut:

let cylinderVolume radius length : float =
   // Define a local value pi.
   let pi = 3.14159
   length * pi * radius * radius

Seperti kode yang ditulis di atas, pengompilasi menerapkan float ke seluruh fungsi; jika Anda bermaksud menerapkannya ke jenis parameter juga, gunakan kode berikut:

let cylinderVolume (radius : float) (length : float) : float

Memanggil Fungsi

Anda memanggil fungsi dengan menentukan nama fungsi diikuti oleh spasi dan kemudian argumen yang dipisahkan oleh spasi. Misalnya, untuk memanggil fungsi cylinderVolume dan menetapkan hasilnya ke nilai vol, Anda dapat menulis kode berikut:

let vol = cylinderVolume 2.0 3.0

Aplikasi Parsial Argumen

Jika menyediakan lebih sedikit dari jumlah argumen yang ditentukan, Anda membuat fungsi baru yang mengharapkan argumen sisa. Metode penanganan argumen ini disebut sebagai currying dan merupakan karakteristik bahasa pemrogram fungsi seperti F#. Misalnya, Anda bekerja dengan dua ukuran alur: satu memiliki radius 2,0 dan satunya memiliki radius 3,0. Anda bisa membuat fungsi yang menentukan volume alur seperti berikut:

let smallPipeRadius = 2.0
let bigPipeRadius = 3.0

// These define functions that take the length as a remaining
// argument:

let smallPipeVolume = cylinderVolume smallPipeRadius
let bigPipeVolume = cylinderVolume bigPipeRadius

Kemudian, Anda dapat memberikan argumen terakhir sesuai kebutuhan untuk berbagai panjang alur dari dua ukuran yang berbeda:

let length1 = 30.0
let length2 = 40.0
let smallPipeVol1 = smallPipeVolume length1
let smallPipeVol2 = smallPipeVolume length2
let bigPipeVol1 = bigPipeVolume length1
let bigPipeVol2 = bigPipeVolume length2

Fungsi Rekursif

Fungsi rekursif adalah fungsi yang memanggil dirinya sendiri. Fungsi ini mengharuskan Anda menentukan kata kunci rec mengikuti kata kunci let. Panggil fungsi rekursif dari dalam bagian isi fungsi sama seperti saat Anda akan memanggil fungsi lain. Fungsi rekursif berikut melakukan komputasi pada nomor Fibonacci nth. Urutan nomor Fibonacci telah dikenal sejak lama dan merupakan urutan yang setiap angka berturut-turut adalah jumlah dari dua angka sebelumnya dalam urutan.

let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)

Beberapa fungsi rekursif mungkin meluap ke tumpukan program atau berjalan tidak efisien jika Anda tidak menulisnya dengan hati-hati dan dengan pengetahuan teknik khusus, seperti penggunaan rekursi ekor, akumulator, dan kelanjutan.

Nilai Fungsi

Dalam F#, semua fungsi dianggap sebagai nilai; bahkan, fungsi itu dikenal sebagai nilai fungsi. Karena fungsi adalah nilai, fungsi dapat digunakan sebagai argumen untuk fungsi lain atau dalam konteks lain ketika nilai digunakan. Berikut ini adalah contoh fungsi yang menggunakan nilai fungsi sebagai argumen:

let apply1 (transform : int -> int ) y = transform y

Anda menentukan jenis nilai fungsi menggunakan token ->. Di sisi kiri token ini adalah jenis argumen, dan di sisi kanan adalah nilai yang ditampilkan. Dalam contoh sebelumnya, apply1 adalah fungsi yang menggunakan fungsi transform sebagai argumen, saat transform adalah fungsi yang menggunakan bilangan bulat dan menampilkan bilangan bulat lain. Contoh kode berikut menunjukkan cara menggunakan apply1:

let increment x = x + 1

let result1 = apply1 increment 100

Nilai result akan menjadi 101 setelah kode sebelumnya berjalan.

Beberapa argumen dipisahkan oleh token -> berturut-turut, seperti yang ditunjukkan dalam contoh berikut:

let apply2 ( f: int -> int -> int) x y = f x y

let mul x y = x * y

let result2 = apply2 mul 10 20

Hasilnya adalah 200.

Ekspresi Lambda

Ekspresi lambda adalah fungsi tanpa nama. Dalam contoh sebelumnya, sebagai ganti mendefinisikan fungsi bernama increment dan mul, Anda dapat menggunakan ekspresi lambda sebagai berikut:

let result3 = apply1 (fun x -> x + 1) 100

let result4 = apply2 (fun x y -> x * y ) 10 20

Anda menentukan ekspresi lambda menggunakan kata kunci fun. Ekspresi lambda menyerupai definisi fungsi, kecuali sebagai ganti token =, token -> digunakan untuk memisahkan daftar argumen dari bagian isi fungsi. Seperti dalam definisi fungsi biasa, jenis argumen dapat disimpulkan atau ditentukan secara eksplisit, dan jenis ekspresi lambda yang ditampilkan akan disimpulkan dari jenis ekspresi terakhir dalam bagian isi. Untuk informasi selengkapnya, lihat Ekspresi Lambda: funKata Kunci.

Pipelines

Operator alur |> digunakan secara ekstensif saat memproses data di F#. Operator ini memungkinkan Anda untuk membuat "alur" fungsi dengan cara yang fleksibel. Dengan alur, panggilan fungsi dapat dirantai bersama sebagai operasi berturut-turut:

let result = 100 |> function1 |> function2

Contoh berikut menjelaskan cara menggunakan operator ini untuk membangun alur fungsional sederhana:


/// Square the odd values of the input and add one, using F# pipe operators.
let squareAndAddOdd values =
    values
    |> List.filter (fun x -> x % 2 <> 0)
    |> List.map (fun x -> x * x + 1)

let numbers = [ 1; 2; 3; 4; 5 ]

let result = squareAndAddOdd numbers

Hasilnya adalah [2; 10; 26]. Sampel sebelumnya menggunakan fungsi pemrosesan daftar, menunjukkan cara fungsi dapat digunakan untuk memproses data saat membangun alur. Operator alur itu sendiri didefinisikan di pustaka inti F# sebagai berikut:

let (|>) x f = f x

Komposisi fungsi

Fungsi dalam F# dapat terdiri dari fungsi lain. Komposisi dua fungsi function1 dan function2 adalah fungsi lain yang mewakili aplikasi function1 yang mengikuti aplikasi function2:

let function1 x = x + 1
let function2 x = x * 2
let h = function1 >> function2
let result5 = h 100

Hasilnya adalah 202.

Operator komposisi >> menggunakan dua fungsi dan menampilkan fungsi; sebaliknya, operator alur |> menggunakan nilai serta fungsi dan menampilkan nilai. Contoh kode berikut menunjukkan perbedaan antara operator alur dan komposisi dengan menunjukkan perbedaan dalam tanda tangan serta penggunaan fungsi.

// Function composition and pipeline operators compared.

let addOne x = x + 1
let timesTwo x = 2 * x

// Composition operator
// ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3
let Compose2 = addOne >> timesTwo

// Backward composition operator
// ( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
let Compose1 = addOne << timesTwo

// Result is 5
let result1 = Compose1 2

// Result is 6
let result2 = Compose2 2

// Pipelining
// Pipeline operator
// ( |> ) : 'T1 -> ('T1 -> 'U) -> 'U
let Pipeline2 x = addOne x |> timesTwo

// Backward pipeline operator
// ( <| ) : ('T -> 'U) -> 'T -> 'U
let Pipeline1 x = addOne <| timesTwo x

// Result is 5
let result3 = Pipeline1 2

// Result is 6
let result4 = Pipeline2 2

Membebani Fungsi Secara Berlebih

Anda dapat membebani secara berlebih metode jenis tetapi tidak dengan fungsi. Untuk informasi selengkapnya, lihat Metode.

Lihat juga