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 fullNamearacılığı mapkod 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 nameListhem sağlayan bir nesnedir firstNameve 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 Maybetü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 fullNamefonksiyonumuzu 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->btüründen diğerine abaşka bir türe b.
Örneğin a, Stringtür, bSayı türü ve fbir dizeyi uzunluğuna eşleyen işlevdir:
// f :: String -> Number
f = str => str.length
Burada a = Stringtüm dizelerin b = Numberkümesini ve tüm sayı kümesini temsil eder . Bu anlamda, hem ave 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
Arraybirç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 atü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]aArrayString[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 atü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, ArrayFunctor'un ikinci kısmı - morfizm kısmı. Ki bu morfizmanın eşler f :: a -> bbir morfizma içine [f] :: [a] -> [b]:
// a -> [a]
Array.map(f) = arr => arr.map(f)
Burada arrtip değerleri ile istenilen uzunlukta bir dizidir ave arr.map(f)tip değerleriyle aynı uzunlukta dizi bgirişleri uygulamak aşağıdaki sonuçları, fgiriş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 .