Functional programming (FP) atau pemrograman fungsional memberikan banyak keuntungan, dan kini popularitasnya telah meningkat sebagai hasilnya. Namun, setiap paradigma pemrograman datang dengan jargon uniknya masing-masing dan FP tidak terkecuali. Dengan memberikan glosarium, kami berharap dapat mempermudah belajar FP.
Contoh yang ada disajikan dalam JavaScript (ES2015). Kenapa JavaScript?
Ini adalah sebuah WIP dari Functional Programming Jargon milik hemanth; Jangan ragu untuk mengirim PR ;)
Jika ada, dokumen ini menggunakan istilah yang didefinisikan dalam spesifikasi Fantasy Land.
Daftar Isi
- Arity
- Higher-Order Functions (HOF)
- Partial Application
- Currying
- Closure
- Auto Currying
- Function Composition
- Continuation
- Purity
- Side Effect
- Idempotent
- Point-Free Style
- Predicate
- Contract
- Category
- Value
- Constant
- Functor
- Pointed Functor
- Lift
- Referential Transparency
- Equational Reasoning
- Lambda
- Lambda Calculus
- Lazy evaluation
- Monoid
- Monad
- Comonad
- Applicative Functor
- Morphism
- Setoid
- Semigroup
- Foldable
- Type Signature
- Algebraic data type
- Option
- Pustaka Pemrograman Fungsional dalam JavaScript
Arity merupakan banyaknya argumen yang diambil oleh fungsi. Berasal dari kata-kata seperti unary, binary, ternary, dan lain-lain. Kata ini memiliki perbedaan yang terdiri dari dua sufiks, "-ary" dan "-ity." Penjumlahan, misalnya, mengambil dua argumen, dan jadi didefinisikan sebagai fungsi biner (binary function) atau fungsi dengan dua arity. Fungsi semacam itu terkadang disebut "dyadic" oleh orang-orang yang lebih menyukai bahasa Yunani dari bahasa Latin. Demikian juga, fungsi yang mengambil sejumlah variabel argumen disebut "variadic", sedangkan fungsi biner harus diberikan dua dan hanya dua argumen, meskipun currying dan partial application (lihat di bawah).
const sum = (a, b) => a + b
const arity = sum.length
console.log(arity) // 2
// Arity dari fungsi `sum` adalah dua
Higher-Order Function adalah sebuah fungsi yang mengambil fungsi sebagai argumen dan/atau mengembalikan sebuah fungsi.
const filter = (predicate, xs) => xs.filter(predicate)
const is = (type) => (x) => Object(x) instanceof type
filter(is(Number), [0, '1', 2, null]) // [0, 2]
Menerapkan fungsi secara parsial (Partial Application atau Fungsi Parsial) artinya membuat fungsi baru dengan mengisi beberapa argumen ke fungsi semula.
// Helper membuat sebagian fungsi yang diaplikasikan
// Mengambil sebuah fungsi dan beberapa argumen
const partial = (f, ...args) =>
// mengembalikan sebuah fungsi yang mengambil sisa argumen
(...moreArgs) =>
// dan memanggil fungsi asilnya dengan semuanya
f(...args, ...moreArgs)
// Sesuatu untuk diaplikasikan
const add3 = (a, b, c) => a + b + c
// Menerapkan `2` dan `3` secara parsial ke `add3`
// Sehingga, memberikan Anda sebuah fungsi dengan satu argumen
const fivePlus = partial(add3, 2, 3) // (c) => 2 + 3 + c
fivePlus(4) // 9
Anda juga dapat menggunakan Function.prototype.bind
untuk menerapkan
fungsi parsial di JavaScript:
const add1More = add3.bind(null, 2, 3) // (c) => 2 + 3 + c
Partial application atau fungsi parsial membantu menciptakan fungsi yang lebih sederhana dari yang lebih kompleks dengan memadukan data saat Anda memilikinya. Curried function sudah secara otomatis diterapkan secara parsial.
Currying merupakan sebuah proses mengubah fungsi yang membutuhkan banyak argumen menjadi fungsi yang membawa mereka satu-persatu.
Setiap kali fungsi dipanggil hanya menerima satu argumen dan mengembalikan sebuah fungsi yang membutuhkan satu argumen sampai semua argumen dilewatkan.
const sum = (a, b) => a + b
const curriedSum = (a) => (b) => a + b
curriedSum(40)(2) // 42.
const add2 = curriedSum(2) // (b) => 2 + b
add2(10) // 12
Closure merupakan sebuah cara untuk mengakses sebuah variabel yang berada di luar cakupannya. Secara formal, closure merupakan sebuah teknik untuk menerapkan lexically scoped bernama binding. Ini adalah cara untuk menyimpan sebuah fungsi dengan sebuah environment.
Closure adalah lingkup yang menangkap variabel lokal dari suatu fungsi untuk askes bahkan setelah eksekusi telah berpindah dari blok yang didefinisikan. Yaitu, mereka membiarkan referensi lingkup setelah blok dimana variabel dinyatakan telah selesai mengeksekusi.
const addTo = x => y => x + y
var addToFive = addTo(5)
addToFive(3) // mengembalikan 8
Fungsi addTo()
mengembalikan sebuah fungsi (secara internal disebut add()
),
lalu disimpan di variabel yang disebut addToFive
dengan curried call yang
memiliki parameter 5
.
Idealnya, ketika fungsi addTo
selesai dieksekusi, cakupannya,
dengan variabel lokal add
, x
, y
seharusnya tidak dapat diakses. Tapi,
itu mengembalikan 8
ketika memanggil addToFive()
. Ini artinya kondisi
dari fungsi addTo
disimpan bahkan setelah blok kode selesai dieksekusi.
Jika tidak, tidak mungkin dapat mengetahui bahwa addTo
telah dipanggil
sebagai addTo(5)
dan nilai dari x
telah ditentukan menjadi 5
.
Lexical scoping adalah alasan mengapa ia dapat menemukan nilai dari x
dan
add
- sebuah variabel private induk yang telah selesai dieksekusi.
Nilai ini disebut Closure.
Stack
beserta lexical scope
fungsinya disimpan dalam bentuk referensi
ke induknya. Hal ini mencegah closure dan variabel-variabel mendasar agar
tidak dikumpulkan sebagai sampah (karena setidaknya ada satu refernsi
langsung untuk itu).
Lambda Vs. Closure
Lambda pada dasarnya adalah fungsi yang didefinisikan secara inline daripada metode standar untuk mendeklarasikan fungsi. Lambda sering dapat dilewatkan sebagai objek.
Closure adalah fungsi yang membungkus keadaan sekitarnya dengan mereferensikan bidang yang ada di luar tubuhnya. State tertutup tetap berada di seberang seruan closure.
Bacaan lebih lanjut/Sumber
Auto currying mengubah fungsi yang membutuhkan banyak argumen menjadi argumen yang jika diberikan kurang dari jumlah argumen yang benar mengembalikan sebuah fungsi yang mengambil sisanya. Bila fungsi mendapatkan jumlah argumen yang benar, maka akan dievaluasi.
lodash dan Ramda memiliki fungsi curry
yang bekerja seperti di bawah.
const add = (x, y) => x + y
const curriedAdd = _.curry(add)
curriedAdd(1, 2) // 3
curriedAdd(1) // (y) => 1 + y
curriedAdd(1)(2) // 3
Bacaan lebih lanjut
Function composition atau komposisi fungsi adalah tindakan yang menempatkan dua fungsi bersama untuk membentuk fungsi ketiga dimana keluaran dari satu fungsi adalah masukan dari yang lain.
const compose = (f, g) => (a) => f(g(a)) // Definisi
const floorAndToString = compose((val) => val.toString(), Math.floor) // Penggunaan
floorAndToString(121.212121) // '121'
Pada suatu titik dalam sebuah program, bagian dari kode yang belum dieksekusi dikenal sebagai kelanjutan/kontinuitas atau continuation.
const printAsString = (num) => console.log(`Given ${num}`)
const addOneAndContinue = (num, cc) => {
const result = num + 1
cc(result)
}
addOneAndContinue(2, printAsString) // 'Given 3'
Kontinuitas sering terlihat pada pemrograman asynchronous saat program perlu menunggu untuk menerima data sebelum dapat melanjutkan. Responnya sering dilewatkan ke sisa program, yang merupakan kelanjutannya, begitu sudah diterima.
const continueProgramWith = (data) => {
// Melanjutkan program dengan data
}
readFileAsync('path/to/file', (err, response) => {
if (err) {
// mengatasi galat
return
}
continueProgramWith(response)
})
Sebuah fungsi dikatan murni atau pure jika mengembalikan nilai yang hanya ditentukan oleh nilai masukannya, dan tidak menghasilkan efek samping atau side effect.
const greet = (name) => `Hi, ${name}`
greet('Brianne') // 'Hi, Brianne'
Berbeda dengan masing-masing hal di bawah:
window.name = 'Brianne'
const greet = () => `Hi, ${window.name}`
greet() // "Hi, Brianne"
Contoh keluaran di atas didasarkan pada data yang tersimpan di luar fungsi...
let greeting
const greet = (name) => {
greeting = `Hi, ${name}`
}
greet('Brianne')
greeting // "Hi, Brianne"
... dan yang satu ini memodifikasi keadaan di luar fungsi.
Sebuah fungsi atau ekspresi dikatakan memiliki efek samping jika selain mengembalikan nilai, ia berinterasksi dengan (membaca dari atau menulis ke) keadaan yang dapat berubah eksternal.
const differentEveryTime = new Date()
console.log('IO is a side effect!')
Suatu fungsi idempotent jika mengaplikasikannya kembali hasilnya tidak menghasilkan hasil yang berbeda.
f(f(x)) ≍ f(x)
Math.abs(Math.abs(10))
sort(sort(sort([2, 1])))
Menulis fungsi dimana definisi tidak secara eksplisit mengidentifikasi argumen yang digunakan. Gaya ini biasanya memerlukan currying atau lainnya Higher-Order function. Alias, Tacit programming.
// Diberikan
const map = (fn) => (list) => list.map(fn)
const add = (a) => (b) => a + b
// Lalu
// Bukan points-free - `numbers` merupakan argumen eksplisit
const incrementAll = (numbers) => map(add(1))(numbers)
// Points-free - `list` merupakan argumen implisit
const incrementAll2 = map(add(1))
incrementAll
mengidentifikasi dan menggunakan parameter numbers
, jadi itu
bukan points-free. incrementAll2
dituliskan hanya dengan menggabungkan
beberapa fungsi dan beberapa nilai, membuatnya tidak menyebut satu pun
argumennya. Itu adalah points-free.
Definisi points-free function terlihat seperti assignment normal tanpa
function
atau =>
.
Suatu predicate adalah sebuah fungsi yang mengembalikan nilai true
atau
false
untuk suatu nilai yang diberikan. Biasanya digunakan sebagai callback
untuk menyaring array.
const predicate = (a) => a > 2
;[1, 2, 3, 4].filter(predicate) // [3, 4]
Suatu contract menentukan kewajiban dan jaminan perilaku dari suatu fungsi atau ekspresi saat runtime. Ini bertindak sebagai seperangkat aturan yang diharapkan dari masukan dan keluaran suatu fungsi atau ekspresi, dan kesalahan umumnya dilaporkan setiap kali sebuah kontrak dilanggar.
// Mendefinisikan contract kami : int -> int
const contract = (input) => {
if (typeof input === 'number') return true
throw new Error('Contract violated: expected int -> int')
}
const addOne = (num) => contract(num) && num + 1
addOne(2) // 3
addOne('some string') // Contract violated: expected int -> int
Kategori dalam category theory adalah kumpulan objek dan morfisme (morphism) di antara keduanya. Dalam pemrograman, biasanya types bertindak sebagai objek dan fungsi sebagai morfisme.
Untuk menjadi kategori yang sah, tiga aturan harus dipenuhi:
- Harus ada morfisme identitas yang memetakan objek itu sendiri.
Dimana
a
adalah sebuah objek dalam beberapa kategori, harus ada fungsi daria -> a
. - Morfisme harus disusun.
Dimana
a
,b
, danc
adalah objek dalam beberapa kategori, danf
adalah morfisme daria -> b
, sertag
adalah morfisme darib -> c
;g(f(x))
harus sama dengan(g • f)(x)
. - Komposisi harus asosiatif.
f • (g • h)
sama halnya dengan(f • g) • h
.
Karena aturan ini mengatur komposisi pada tingkat yang sangat abstrak, teori kategori sangat bagus dalam menemukan cara baru untuk menyusun sesuatu.
Bacaan lebih lanjut
Apa saja yang dapat di-assign ke variabel.
5
Object.freeze({name: 'John', age: 30}) // The `freeze` function enforces immutability.
;(a) => a
;[1]
undefined
Sebuah variabel yang tidak dapat ditetapkan kembali setelah ditentukan nilainya.
const five = 5
const john = Object.freeze({name: 'John', age: 30})
Constant atau konstanta adalah referentially transparent. Artinya, mereka dapat diganti dengan nilai yang mereka wakili tanpa mempengaruhi hasilnya.
Dengan dua konstanta di atas, ekspresi berikut akan selalu mengembalikan
nilai true
.
john.age + five === ({name: 'John', age: 30}).age + (5)
Suatu objek yang mengimplementasikan fungsi map
, yang ketika menjalankan
lebih dari setiap nilai pada objek untuk menghasilkan objek baru, mematuhi
dua aturan:
Preserves identity
object.map(x => x) ≍ object
Composable
object.map(compose(f, g)) ≍ object.map(g).map(f)
(f
, g
menjadi fungsi sewenang-wenang)
Functor umum dalam JavaScript adalah Array
karena mematuhi dua aturan
functor, yaitu:
[1, 2, 3].map(x => x) // = [1, 2, 3]
dan
const f = x => x + 1
const g = x => x * 2
;[1, 2, 3].map(x => f(g(x))) // = [3, 5, 7]
;[1, 2, 3].map(g).map(f) // = [3, 5, 7]
Suatu objek dengan sebuah fungsi of
yang mengambil semua nilai tunggal
ke dalamnya.
ES2015 menambahkan Array.of
yang menjadikannya pointed functor.
Array.of(1) // [1]
Lifting atau mengangkat (dari kata lift, angkat) adalah saat Anda mengambil sebuah nilai dan mengambilnya ke dalam suatu objek seperti functor. Jika Anda mengangkat sebuah fungsi ke dalam Applicative Functor, maka Anda dapat membuatnya bekerja pada nilai-nilai yang juga ada di functor itu.
Beberapa implementasi memiliki fungsi yang disebut lift
, atau liftA2
agar
lebih mudah menjalankan fungsi pada functor.
const liftA2 = (f) => (a, b) => a.map(f).ap(b) // catatan: itu `ap`, bukan `map`.
const mult = a => b => a * b
const liftedMult = liftA2(mult) // fungsi ini sekarang bekerja pada functor seperti array
liftedMult([1, 2], [3]) // [3, 6]
liftA2(a => b => a + b)([1, 2], [3, 4]) // [4, 5, 5, 6]
Mengangkat fungsi satu argumen dan menerapkannya melakukan hal yang sama
seperti map
.
const increment = (x) => x + 1
lift(increment)([2]) // [3]
;[2].map(increment) // [3]
Sebuah ekspresi yang dapat diganti nilainya dengan tanpa mengubah tingkah laku program tersebut dikatan referentially transparan.
Katakanlah kita memiliki fungsi greet
:
const greet = () => 'Hello World!'
Setiap seruan dari greet()
dapat ditimpa dengan Hello World!
, karena itu
greet
secara referensial transparan.
Ketika sebuah aplikasi terdiri dari ekspresi dan tanpa efek samping, kebenaran tentang sistem dapat diturunkan dari bagian-bagiannya.
Fungsi anonim yang dapat diperlakukan seperti sebuah nilai.
;(function (a) {
return a + 1
})
;(a) => a + 1
Lambda juga sering dilewatkan sebagai argumen ke Higher-Order function.
[1, 2].map((a) => a + 1) // [2, 3]
Anda dapat menugaskan (assign) suatu lambda ke dalam sebuah variabel.
const add1 = (a) => a + 1
Sebuah cabang dari matematika yang menggunakan fungsi untuk membuat suatu model universal dari komputasi.
Lazy evaluation adalah mekanisme evaluasi panggilan-per-kebutuhan yang menunda evaluasi suatu ekspresi sampai nilainya dibutuhkan. Dalam bahasa fungsional, ini memungkinkan struktur seperti infinite list, yang biasanya tidak tersedia dalam bahasa imperatif dimana urutan perintah sangat penting.
const rand = function*() {
while (1 < 2) {
yield Math.random()
}
}
const randIter = rand()
randIter.next() // Setiap eksekusi memberikan nilai acak, ekspresi dievaluasi hanya saat dibutuhkan
Objek dengan fungsi yang "menggabungkan" objek itu sendiri dengan tipe lain yang sama.
Salah satu monoid sederhana adalah penjumlahan angka:
1 + 1 // 2
Dalam kasus ini, angka adalah objek dan +
adalah fungsi.
Nilai "identitas" juga harus ada bila dikombinasikan dengan nilai yang tidak mengubahnya.
Nilai identitas untuk penjumlahan adalah 0
.
1 + 0 // 1
Ini juga memerlukan pengelompokkan operasi yang tidak akan mempengaruhi hasilnya (asosiatif):
1 + (2 + 3) === (1 + 2) + 3 // true
Rangkaian array juga membentuk monoid:
;[1, 2].concat([3, 4]) // [1, 2, 3, 4]
Nilai identitasnya adalah array kosong atau []
.
;[1, 2].concat([]) // [1, 2]
Jika fungsi identitas dan komposisi disediakan, maka fungsinya membentuk monoid:
const identity = (a) => a
const compose = (f, g) => (x) => f(g(x))
foo
adalah fungsi apapun yang mengambil satu argumen.
compose(foo, identity) ≍ compose(identity, foo) ≍ foo
Monad adalah sebuah objek dengan fungsi of
dan chain
.
chain
ini seperti map
, kecuali itu "membatalkan" objek
bersarang yang dihasilkan.
// Implementasi
Array.prototype.chain = function (f) {
return this.reduce((acc, it) => acc.concat(f(it)), [])
}
// Penggunaan
;Array.of('cat,dog', 'fish,bird').chain((a) => a.split(',')) // ['cat', 'dog', 'fish', 'bird']
// Kontras ke map
;Array.of('cat,dog', 'fish,bird').map((a) => a.split(',')) // [['cat', 'dog'], ['fish', 'bird']]
of
juga diketahui sebagai return
di bahasa fungsional lainnya.
chain
juga diketahui sebagai flatmap
dan bind
di bahasa lainnya.
Suatu objek yang memiliki fungsi extract
dan extend
.
const CoIdentity = (v) => ({
val: v,
extract () {
return this.val
},
extend (f) {
return CoIdentity(f(this))
}
})
extract
mengambil sebuah nilai keluar dari functor.
CoIdentity(1).extract() // 1
extend menjalankan fungsi di atas comonad. Fungsi tersebut seharusnya mengembalikan tipe yang sama dengan comonad.
CoIdentity(1).extend((co) => co.extract() + 1) // CoIdentity(2)
Suatu applicative functor adalah sebuah objek dengan fungsi ap
. ap
menerapkan fungsi pada objek ke nilai objek lain dari tipe yang sama.
// Implementasi
Array.prototype.ap = function (xs) {
return this.reduce((acc, f) => acc.concat(xs.map(f)), [])
}
// Contoh penggunaan
;[(a) => a + 1].ap([1]) // [2]
Ini berguna jika Anda memiliki dua objek dan Anda ingin menerapkan fungsi biner ke isinya.
// Array yang ingin digabungkan
const arg1 = [1, 3]
const arg2 = [4, 5]
// menggabungkan fungsi - harus curried untuk pekerjaan ini
const add = (x) => (y) => x + y
const partiallyAppliedAdds = [add].ap(arg1) // [(y) => 1 + y, (y) => 3 + y]
Ini memberi Anda sebuah array dari sejumlah fungsi yang dapat Anda sebut ap
untuk mendapatkan hasilnya:
partiallyAppliedAdds.ap(arg2) // [5, 6, 7, 8]
Sebuah fungsi transformasi.
Sebuah fungsi dimana tipe masukannya sama dengan keluarannya.
// uppercase :: String -> String
const uppercase = (str) => str.toUpperCase()
// decrement :: Number -> Number
const decrement = (x) => x - 1
Sepasang transformasi antara dua jenis benda yang bersifat struktural dan tidak ada data yang hilang.
Sebagai contoh, koordinat 2D dapat disimpan sebagai array [2, 3]
atau objek
{x: 2, y: 3}
.
// Menyediakan fungsi untuk mengubah kedua arah membuat mereka isomorfik
const pairToCoords = (pair) => ({x: pair[0], y: pair[1]})
const coordsToPair = (coords) => [coords.x, coords.y]
coordsToPair(pairToCoords([1, 2])) // [1, 2]
pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2}
Suatu objek yang memiliki fungsi equals
yang mana dapat digunakan untuk
membandingkan objek lain dengan tipe yang sama.
Menjadikan array suatu setoid:
Array.prototype.equals = function (arr) {
const len = this.length
if (len !== arr.length) {
return false
}
for (let i = 0; i < len; i++) {
if (this[i] !== arr[i]) {
return false
}
}
return true
}
;[1, 2].equals([1, 2]) // true
;[1, 2].equals([0]) // false
Suatu objek yang memiliki fungsi concat
yang menggabungkannya dengan objek
lain dengan tipe yang sama.
;[1].concat([2]) // [1, 2]
Suatu objek yang memiliki fungsi reduce
yang dapat mengubah objek tersebut
menjadi tipe yang lain.
const sum = (list) => list.reduce((acc, val) => acc + val, 0)
sum([1, 2, 3]) // 6
Seringkali fungsi dalam JavaScript memiliki komentar yang menunjukkan tipe dari argumen dan nilai pengembaliannya.
Ada sedikit perbedaan di antara komunitas/masyarakat, namun mereka sering mengikuti pola berikut:
// functionName :: firstArgType -> secondArgType -> returnType
// add :: Number -> Number -> Number
const add = (x) => (y) => x + y
// increment :: Number -> Number
const increment = (x) => x + 1
Jika suatu fungsi menerima fungsi lain sebagai argumennya, maka itu dibungkus dengan tanda kurung.
// call :: (a -> b) -> a -> b
const call = (f) => (x) => f(x)
Huruf a
, b
, c
, d
digunakan sebagai tanda bahwa argumen tersebut dapat
berbentuk apa saja. Layaknya versi dari map
, mengambil sebuah fungsi
yang mengubah nilai dari bentuk a
ke bentuk lain b
, sebuah array dengan
nilai berbentuk a
, dan mengembalikan sebuah array dengan nilai berbentuk
b
.
// map :: (a -> b) -> [a] -> [b]
const map = (f) => (list) => list.map(f)
Bacan lebih lanjut
- Ramda's type signatures
- Mostly Adequate Guide
- What is Hindley-Milner? di Stack Overflow
Jenis komposit yang dibuat dari jenis lainnya. Dua kelas umum dari tipe aljabar (algebraic type) adalah sum dan product.
Sum type adalah kombinasi dari dua type menjadi satu sama lain. Ini disebut jumlah (sum) karena jumlah nilai yang mungkin terjadi pada type hasil adalah jumlah dari tipe masukan.
JavaScript tidak memiliki type seperti ini, tapi kita dapat menggunakan Set
untuk berpura-pura:
// bayangkan bahwa daripada Set di sini kita memiliki tipe yang hanya memiliki nilai-nilai ini
const bools = new Set([true, false])
const halfTrue = new Set(['half-true'])
// Tipe `weakLogic` mengandung jumlah nilai dari `bools` dan `halfTrue`
const weakLogicValues = new Set([...bools, ...halfTrue])
Sum type terkadang disebut union type, discriminated union, atau tagged union.
Ada beberapa pustaka dalam JavaScript yang membantu mendefinisikan dan menggunakan union type.
Flow memasukkan union type dan TypeScript memiliki Enums untuk melayani peran yang sama.
Tipe product menggabungkan beberapa tipe bersama, dengan cara yang mungkin Anda telah akrab:
// point :: (Number, Number) -> {x: Number, y: Number}
const point = (x, y) => ({x: x, y: y})
Ini disebut produk (product) karena nilai total dari struktur data adalah produk dari nilai yang berbeda. Banyak bahasa memiliki tipe tuple yang merupakan formulasi sederhana dari product type.
Lihat juga teori himpunan.
Option adalah suatu sum type dengan dua kasus yang sering
disebut Some
dan None
.
Option sangat berguna untuk menyusun fungsi-fungsi yang mungkin tidak mengembalikan sebuah nilai.
// Definisi naif
const Some = (v) => ({
val: v,
map (f) {
return Some(f(this.val))
},
chain (f) {
return f(this.val)
}
})
const None = () => ({
map (f) {
return this
},
chain (f) {
return this
}
})
// maybeProp :: (String, {a}) -> Option a
const maybeProp = (key, obj) => typeof obj[key] === 'undefined' ? None() : Some(obj[key])
Gunakan chain
untuk mengurutkan fungsi yang mengembalikan Option
.
// getItem :: Cart -> Option CartItem
const getItem = (cart) => maybeProp('item', cart)
// getPrice :: Item -> Option Number
const getPrice = (item) => maybeProp('price', item)
// getNestedPrice :: cart -> Option a
const getNestedPrice = (cart) => getItem(obj).chain(getPrice)
getNestedPrice({}) // None()
getNestedPrice({item: {foo: 1}}) // None()
getNestedPrice({item: {price: 9.99}}) // Some(9.99)
Option
juga dikenal sebagai Maybe
. Some
terkadang disebut Just
.
None
terkadang disebut Nothing
.
- mori
- Immutable
- Ramda
- ramda-adjunct
- Folktale
- monet.js
- lodash
- Underscore.js
- Lazy.js
- maryamyriameliamurphies.js
- Haskell in ES6
P.S: Repository ini di-fork dari proyek Functional Programming Jargon milik hemanth dan telah dikatakan berhasil karena kontribusi yang luar biasa.