Genel Bakış
Fonksiyonel programlamada, bir functor aslında sıradan birliği kaldırma yapısıdır yeni tür değişkenler arasındaki fonksiyonlara fonksiyonların (yani bir argümanı olanların) . Düz nesneler arasında basit işlevler yazmak ve sürdürmek ve bunları kaldırmak için işlevler kullanmak, ardından karmaşık kap nesneleri arasında manuel olarak işlevler yazmak çok daha kolaydır. Diğer bir avantaj, düz işlevleri yalnızca bir kez yazmak ve daha sonra farklı işlevler aracılığıyla yeniden kullanmaktır.
Functorlara örnek olarak diziler, "belki" ve "ya" functorları, vadeli işlemler (bakınız örn. Https://github.com/Avaq/Fluture ) ve diğerleri dahildir.
örnekleme
Ad ve soyadından tam kişinin adını oluşturan işlevi göz önünde bulundurun. Bunu fullName(firstName, lastName)
iki argümanın işlevi olarak tanımlayabiliriz , ancak bu yalnızca bir argümanın işlevleriyle ilgilenen işlevler için uygun olmaz. Çözümlemek için, tüm argümanları name
şimdi fonksiyonun tek argümanı olan tek bir nesnede topluyoruz :
// In JavaScript notation
fullName = name => name.firstName + ' ' + name.lastName
Peki ya bir dizide çok sayıda insan varsa? Elle listenin üzerine gitmek yerine, biz sadece bizim işlevini yeniden kullanabilirsiniz fullName
aracılığı map
kod kısa tek bir satır Dizilerin için sağlanan yöntemle:
fullNameList = nameList => nameList.map(fullName)
ve onu gibi kullan
nameList = [
{firstName: 'Steve', lastName: 'Jobs'},
{firstName: 'Bill', lastName: 'Gates'}
]
fullNames = fullNameList(nameList)
// => ['Steve Jobs', 'Bill Gates']
Biz bir aile odada her giriş olduğunda Yani, çalışacak nameList
hem sağlayan bir nesnedir firstName
ve lastName
özelliklerini. Ama ya bazı nesneler hiç nesne değilse (ya da hiç nesne değilse)? Hatalardan kaçınmak ve kodu daha güvenli hale getirmek için, nesnelerimizi Maybe
türe sarabiliriz (ör. Https://sanctuary.js.org/#maybe-type ):
// function to test name for validity
isValidName = name =>
(typeof name === 'object')
&& (typeof name.firstName === 'string')
&& (typeof name.lastName === 'string')
// wrap into the Maybe type
maybeName = name =>
isValidName(name) ? Just(name) : Nothing()
burada Just(name)
yalnızca geçerli adları taşıyan bir konteyner ve Nothing()
diğer her şey için kullanılan özel değerdir. Şimdi, argümanlarımızın geçerliliğini kontrol etmek için kesintiye uğratmak (veya unutmak) yerine, orijinal fullName
fonksiyonumuzu başka bir tek satırlık kodla tekrar kullanabiliriz (kaldırabiliriz) map
, bu kez Belki de bu tür için sağlanan:
// Maybe Object -> Maybe String
maybeFullName = maybeName => maybeName.map(fullName)
ve onu gibi kullan
justSteve = maybeName(
{firstName: 'Steve', lastName: 'Jobs'}
) // => Just({firstName: 'Steve', lastName: 'Jobs'})
notSteve = maybeName(
{lastName: 'SomeJobs'}
) // => Nothing()
steveFN = maybeFullName(justSteve)
// => Just('Steve Jobs')
notSteveFN = maybeFullName(notSteve)
// => Nothing()
Kategori Teorisi
Bir Funktör içinde Kategori Teorisi kendi Morfizmlerin bileşimin saygı bu iki grup arasında bir haritasıdır. Bir de Bilgisayar Dili , ilgi ana kategorisi olan biridir nesneler olan tipleri olan (değerlerin belirli setleri) ve morfizimler olan fonksiyonları f:a->b
türünden diğerine a
başka bir türe b
.
Örneğin a
, String
tür, b
Sayı türü ve f
bir dizeyi uzunluğuna eşleyen işlevdir:
// f :: String -> Number
f = str => str.length
Burada a = String
tüm dizelerin b = Number
kümesini ve tüm sayı kümesini temsil eder . Bu anlamda, hem a
ve hem de Kategori Kategorisindekib
nesneleri temsil eder (bu türler kategorisi ile yakından ilişkilidir, fark burada önemsizdir). Set Kategorisinde, iki set arasındaki morfizmler ilk setten ikinciye kadar tüm fonksiyonlardır. Buradaki uzunluk fonksiyonumuz , dizelerden sayı kümesine bir morfizmdir.f
Sadece belirlenmiş kategoriyi göz önüne aldığımızda, ilgili Functors kendi başına, belirli cebirsel yasaları karşılayan nesnelere ve morfizmlere nesne gönderen haritalardır.
Misal: Array
Array
birçok şey anlamına gelebilir, ancak yalnızca bir şey bir Functor'dur - tür yapısı, bir türü tüm tür dizilerinin a
türüyle eşleştirir . Örneğin, funktoru türünü eşler türü içine (istenilen uzunlukta dizeleri tüm diziler kümesi) ve kümesi türü tekabül türü içine (sayılar tüm diziler kümesi).[a]
a
Array
String
[String]
Number
[Number]
Functor haritasını karıştırmamak önemlidir
Array :: a => [a]
bir morfizm ile a -> [a]
. Funktor basitçe tipini (ortakları) eşler a
türü içine [a]
başka bir şey olarak. Her türün aslında bir dizi unsur olması, burada bir ilgisi yoktur. Aksine, bir morfizm bu kümeler arasındaki gerçek bir işlevdir. Örneğin, doğal bir morfizm (işlev) vardır
pure :: a -> [a]
pure = x => [x]
1 öğeli diziye bu değeri tek giriş olarak bir değer gönderir. Bu işlev Functor'ın bir parçası değildirArray
! Bu fonksiyonun bakış açısından pure
, sadece diğerleri gibi bir fonksiyon, özel bir şey değil.
Öte yandan, Array
Functor'un ikinci kısmı - morfizm kısmı. Ki bu morfizmanın eşler f :: a -> b
bir morfizma içine [f] :: [a] -> [b]
:
// a -> [a]
Array.map(f) = arr => arr.map(f)
Burada arr
tip değerleri ile istenilen uzunlukta bir dizidir a
ve arr.map(f)
tip değerleriyle aynı uzunlukta dizi b
girişleri uygulamak aşağıdaki sonuçları, f
girişlere arr
. Bunu bir işlev haline getirmek için, kimliği kimliğe ve kompozisyonları kompozisyonlara eşlemenin matematiksel yasaları bu Array
örnekte kontrol edilmesi kolay olmalıdır .