İşlev nesnesi - Function object

İçinde bilgisayar Programlama, bir işlev nesnesi[a] izin veren bir yapıdır nesne sıradanmış gibi çağrılmak veya çağrılmak işlevi, genellikle aynı sözdizimiyle (bir işlev de olabilen bir işlev parametresi). İşlev nesneleri genellikle denir functors.

Açıklama

Bir işlev nesnesinin tipik bir kullanımı yazılıdır geri çağırmak fonksiyonlar. Bir geri arama prosedürel diller, gibi C kullanılarak gerçekleştirilebilir işlev işaretçileri.[2] Bununla birlikte, bir durumu geri arama işlevine veya işlevinden çıkarmak zor veya garip olabilir. Bu kısıtlama aynı zamanda işlevin daha dinamik davranışını da engeller. Bir işlev nesnesi bu sorunları çözer çünkü işlev gerçekten bir cephe tam bir nesne için, kendi durumunu taşıyan.

Birçok modern (ve bazıları daha eski) dil, ör. C ++, Eyfel, Harika, Lisp, Smalltalk, Perl, PHP, Python, Yakut, Scala ve diğerleri, destek birinci sınıf işlev nesneler ve hatta bunları önemli ölçüde kullanabilir.[3] Fonksiyonel programlama diller ayrıca destekler kapanışlar, yani yaratma sırasında çevrelerindeki değişkenleri 'kapatabilen' birinci sınıf işlevler. Derleme sırasında, olarak bilinen bir dönüşüm lambda kaldırma kapanışları işlev nesnelerine dönüştürür.

C ve C ++ 'da

Bir öğe çifti arasındaki bir sıralama ilişkisini tanımlamak için bir geri çağırma işlevi kullanan bir sıralama rutini örneğini düşünün. İşlev işaretçileri kullanan bir C programı şu şekilde görünebilir:

#Dahil etmek <stdlib.h>/ * qsort () geriçağırım işlevi, a  b ise 0, a == b ise 0 döndürür * /int karşılaştırma(sabit geçersiz* a, sabit geçersiz* b){    dönüş (*(int *)a - *(int *)b));}...// qsort prototipi// void qsort (void * base, size_t nel, size_t genişlik, int (* karşılaştırma) (const void *, const void *));...int ana(geçersiz){    int öğeler[] = { 4, 3, 1, 2 };    qsort(öğeler, boyutu(öğeler) / boyutu(öğeler[0]), boyutu(öğeler[0]), karşılaştırma);    dönüş 0;}

C ++ 'da, sıradan bir işlev yerine bir işlev nesnesi, bir sınıf tanımlanarak kullanılabilir. aşırı yükler işlev çağrısı operatörü tanımlayarak Şebeke() üye işlevi. C ++ 'da bu aşağıdaki gibi görünebilir:

// karşılaştırıcı yüklem: a yapı IntComparator{  bool Şebeke()(sabit int &a, sabit int &b) sabit  {    dönüş a < b;  }};int ana(){    std::vektör<int> öğeler { 4, 3, 1, 2 };    std::çeşit(öğeler.başla(), öğeler.son(), IntComparator());    dönüş 0;}

Geri aramayı sağlamak için sözdiziminin std :: sort () işlev aynıdır, ancak işlev işaretçisi yerine bir nesne iletilir. Çağrıldığında, geri çağırma işlevi diğer herhangi bir üye işlevi gibi yürütülür ve bu nedenle nesnenin diğer üyelerine (veriler veya işlevler) tam erişime sahiptir. Tabii ki, bu sadece önemsiz bir örnek. Bir functor'un normal bir fonksiyondan daha fazlasını sağladığını anlamak için, nesneleri belirli bir alana göre sıralamanın yaygın kullanım durumunu düşünün. Aşağıdaki örnekte, basit bir çalışan veritabanını her çalışanın kimlik numarasına göre sıralamak için bir işlev kullanılır.

yapı Karşılaştırma{    sabit std::dizi SORT_FIELD;    Karşılaştırma(sabit std::dizi& sort_field="isim")      : SORT_FIELD(sort_field)    {        / * sort_field'ı doğrula * /    }        bool Şebeke()(sabit Çalışan& a, sabit Çalışan& b)    {        Eğer (SORT_FIELD == "isim")            dönüş a.isim < b.isim;        Başka Eğer (SORT_FIELD == "yaş")            dönüş a.yaş < b.yaş;        Başka Eğer (SORT_FIELD == "idnum")            dönüş a.idnum < b.idnum;        Başka            / * istisna falan fırlat * /    }};int ana(){    std::vektör<Çalışan> emps;        / * veritabanını dolduracak kod * /        // Veritabanını çalışan kimlik numarasına göre sıralayın    std::çeşit(emps.başla(), emps.son(), Karşılaştırma("idnum"));        dönüş 0;}

İçinde C ++ 11, lambda ifadesi aynı şeyi yapmanın daha kısa ve öz bir yolunu sağlar.

int ana(){    std::vektör<Çalışan> emps;    / * veritabanını dolduracak kod * /    sabit std::dizi sort_field = "idnum";    std::çeşit(emps.başla(), emps.son(), [&sort_field](sabit Çalışan& a, sabit Çalışan& b){ / * alanı seçmek ve karşılaştırmak için kod * / });    dönüş 0;}


Geri çağırma işlevleri dışındaki durumlarda işlev nesnelerini kullanmak mümkündür. Bu durumda kısaltılmış terim functor normalde değil işlev nesnesi hakkında kullanılır. Örneğe devam edersek,

IntComparator cpm;bool sonuç = cpm(a, b);

C ++ 'da sınıf türü işlevlerine ek olarak, başka tür işlev nesneleri de mümkündür. C ++ 'ın üye göstericisinden veya şablon tesisleri. Şablonların etkileyiciliği, bazılarının fonksiyonel programlama işlev nesnelerini diğer işlev nesneleri açısından tanımlamak gibi kullanılacak teknikler ( işlev bileşimi ). C ++ 'ın çoğu Standart Şablon Kitaplığı (STL), şablon tabanlı işlev nesnelerini yoğun bir şekilde kullanır.

Devleti sürdürmek

İşlev nesnelerinin bir başka avantajı da, onları etkileyen bir durumu sürdürme yetenekleridir Şebeke() aramalar arasında. Örneğin, aşağıdaki kod bir jeneratör 10'dan itibaren sayılır ve 11 kez çağrılır.

#Dahil etmek <algorithm>#Dahil etmek <iostream>#Dahil etmek <iterator>sınıf CountFrom { halka açık:  CountFrom(int Miktar) : Miktar_(Miktar) {}    int Şebeke()() { dönüş Miktar_++; } özel:  int Miktar_;};int ana() {  sabit int durum(10);  std::üretmek_n(std::ostream_iterator<int>(std::cout, " n"), 11,                  CountFrom(durum));}

C ++ 14 veya sonrasında, yukarıdaki örnek şu şekilde yeniden yazılabilir:

#Dahil etmek <algorithm>#Dahil etmek <iostream>#Dahil etmek <iterator>int ana() {  std::üretmek_n(std::ostream_iterator<int>(std::cout, " n"), 11,                  [Miktar=10]() değişebilir { dönüş Miktar++; });}

C #

İçinde C #, işlev nesneleri aracılığıyla bildirilir delegeler. Bir temsilci, adlandırılmış bir yöntem veya bir lambda ifadesi. Burada adlandırılmış bir yöntem kullanan bir örnek verilmiştir.

kullanma Sistem;kullanma System.Collections.Generic;halka açık sınıf Karşılaştırma Sınıfı1{    halka açık statik int Karşılaştırma Fonksiyonu(int x, int y)    {        dönüş x - y;    }    halka açık statik geçersiz Ana()    {        var öğeler = yeni Liste<int> { 4, 3, 1, 2 };        Karşılaştırma<int> del = Karşılaştırma Fonksiyonu;        öğeler.Çeşit(del);    }}

İşte bir lambda ifadesi kullanan bir örnek.

kullanma Sistem;kullanma System.Collections.Generic;halka açık sınıf Karşılaştırma Sınıfı2{    halka açık statik geçersiz Ana()    {        var öğeler = yeni Liste<int> { 4, 3, 1, 2 };        öğeler.Çeşit((x, y) => x - y);    }}

D olarak

D işlev nesnelerini bildirmek için birkaç yol sağlar: Lisp / Python tarzı kapanışlar veya C # tarzı delegeler, sırasıyla:

bool bulmak(T)(T[] samanlık, bool temsilci(T) iğne_ testi) {  her biri için (Saman; samanlık) {    Eğer (iğne_ testi(Saman))      dönüş doğru;  }  dönüş yanlış;}geçersiz ana() {    int[] samanlık = [345, 15, 457, 9, 56, 123, 456];    int   iğne = 123;    bool iğne testi(int n) {      dönüş n == iğne;    }    iddia etmek(bulmak(samanlık, &iğne testi));}

A arasındaki fark temsilci ve bir kapatma D'de otomatik ve muhafazakar bir şekilde derleyici tarafından belirlenir. D ayrıca lambda tarzı bir tanıma izin veren işlev değişmezlerini de destekler:

geçersiz ana() {    int[] samanlık = [345, 15, 457, 9, 56, 123, 456];    int   iğne = 123;    iddia etmek(bulmak(samanlık, (int n) { dönüş n == iğne; }));}

Derleyicinin kodu satır içi yapmasına izin vermek için (yukarıya bakın), işlev nesneleri de C ++ stili ile belirtilebilir. operatör aşırı yükleme:

bool bulmak(T, F)(T[] samanlık, F iğne_ testi) {  her biri için (Saman; samanlık) {    Eğer (iğne_ testi(Saman))      dönüş doğru;  }  dönüş yanlış;}geçersiz ana() {    int[] samanlık = [345, 15, 457, 9, 56, 123, 456];    int   iğne = 123;    sınıf İğne Testi {      int iğne;      bu(int n) { iğne = n; }      bool opCall(int n) {        dönüş n == iğne;      }    }    iddia etmek(bulmak(samanlık, yeni İğne Testi(iğne)));}

Eyfel'de

İçinde Eyfel yazılım geliştirme yöntemi ve dili, işlemler ve nesneler her zaman ayrı kavramlar olarak görülür. Ancak ajan mekanizması, işlemlerin çalışma zamanı nesneleri olarak modellenmesini kolaylaştırır. Aracılar, yordamsal çağrılarda bağımsız değişken olarak iletilme veya geri arama rutinleri olarak belirtilme gibi işlev nesnelerine atfedilen uygulama aralığını karşılar. Eyfel'deki aracı mekanizmasının tasarımı, yöntemin ve dilin nesneye yönelik doğasını yansıtmaya çalışır. Bir ajan, genellikle Eiffel'deki iki tür rutini modelleyen iki kütüphane sınıfından birinin doğrudan bir örneği olan bir nesnedir: PROSEDÜR ve FONKSİYON. Bu iki sınıf, daha soyut olan RUTİN.

Yazılım metni içinde dil anahtar sözcüğü ajan ajanların kompakt bir biçimde oluşturulmasına izin verir. Aşağıdaki örnekte amaç, bir düğmeye tıklandığında yürütülecek eylemler listesine göstergeyi ileriye doğru adımlama eylemini eklemektir.

düğmem.select_actions.uzatmak (ajan my_gauge.öne çık)

Rutin uzatmak Yukarıdaki örnekte başvurulan, grafik kullanıcı arabirimi (GUI) kitaplığındaki bir sınıfın özelliğidir. olay odaklı programlama yetenekleri.

Diğer kütüphane sınıflarında, aracıların farklı amaçlar için kullanıldığı görülmektedir. Veri yapılarını destekleyen bir kitaplıkta, örneğin, doğrusal yapıları modelleyen bir sınıf evrensel nicelik bir işlevi olan hepsi için tip BOOLE bir temsilciyi, bir örneğini kabul eden FONKSİYON, bir argüman olarak. Öyleyse, aşağıdaki örnekte, eylemim yalnızca tüm üyeleri listem '!' karakterini içerir:

    listem: BAĞLANTILI LİSTE [STRING]        ...            Eğer listem.hepsi için (ajan {STRING}.vardır ('!')) sonra                eylemim            son        ...

Aracılar oluşturulduğunda, modelledikleri yordamların argümanları ve hatta uygulandıkları hedef nesne olabilir. kapalı veya sol açık. Kapalı bağımsız değişkenler ve hedeflere, aracı oluşturma sırasında değerler verilir. Açık bağımsız değişkenler ve hedefler için değerlerin atanması, aracı oluşturulduktan sonraki bir noktaya kadar ertelenir. Rutin hepsi için bağımsız değişken olarak, yapı için gerçek genel parametreye uyan bir açık bağımsız değişken veya hedefe sahip bir işlevi temsil eden bir aracı bekler (STRING bu örnekte.)

Bir aracının hedefi açık bırakıldığında, parantez içine alınmış beklenen hedefin sınıf adı, metinde gösterildiği gibi bir nesne referansı ile değiştirilir. temsilci {STRING} .has ('!') yukarıdaki örnekte. Bir bağımsız değişken açık bırakıldığında, soru işareti karakteri ('?'), Açık bağımsız değişken için bir yer tutucu olarak kodlanır.

Açık hedefleri ve argümanları kapatma veya bırakma yeteneği, ajan mekanizmasının esnekliğini geliştirmeyi amaçlar. Yeni bir satırdan sonra standart çıktıya bir dize yazdırmak için aşağıdaki prosedürü içeren bir sınıfı düşünün:

    print_on_new_line (s: STRING)            - Önünde yeni bir satır olan 's' yazdır        yapmak            Yazdır ("% N" + s)        son

Aynı sınıfta olduğu varsayılan aşağıdaki kod parçacığı, print_on_new_line aynı rutinde argüman olarak kullanılan ajanlarda açık argümanların ve açık hedeflerin karıştırılmasını göstermek.

    listem: BAĞLANTILI LİSTE [STRING]        ...            listem.hepsini yap (ajan print_on_new_line (?))            listem.hepsini yap (ajan {STRING}.daha düşük)            listem.hepsini yap (ajan print_on_new_line (?))        ...

Bu örnek prosedürü kullanır hepsini yap Yapıdaki her bir öğe için bir aracı tarafından modellenen rutini yürüten doğrusal yapılar için.

Üç talimat dizisi, dizeleri yazdırır. listem, dizeleri küçük harfe dönüştürür ve ardından yeniden yazdırır.

Prosedür hepsini yap açık bağımsız değişken için mevcut öğeyi ikame eden rutini yürüten yapı boyunca yinelenir (aracıların durumunda print_on_new_line) veya açık hedef (temsilcinin temeli olması durumunda daha düşük).

Açık ve kapalı argümanlar ve hedefler, gerekli sayıda argüman dışında tümünü kapatarak gerekenden daha fazla argüman gerektiren rutinlerin kullanımına da izin verir:

listem.hepsini yap (ajan my_multi_arg_procedure (closed_arg_1, ?, kapalı_arg_2, closed_arg_3)

Eyfel acentesi mekanizması, Eyfel ISO / ECMA standart belgesi.

Java'da

Java yok birinci sınıf işlevler, bu nedenle işlev nesneleri genellikle tek bir yöntemle (en yaygın olarak Aranabilir arabirim), tipik olarak uygulama anonimdir iç sınıf veya Java 8'den başlayarak, a lambda.

Java'nın standart kitaplığından bir örnek için, java.util.Collections.sort () bir tane al Liste ve rolü Listedeki nesneleri karşılaştırmak olan bir işlev. Birinci sınıf işlevler olmadan işlev, Karşılaştırıcı arayüzünün bir parçasıdır. Bu aşağıdaki şekilde kullanılabilir.

Liste<Dize> liste = Diziler.asList("10", "1", "20", "11", "21", "12");		Karşılaştırıcı<Dize> numStringComparator = yeni Karşılaştırıcı<Dize>() {    halka açık int karşılaştırmak(Dize str1, Dize str2) {        dönüş Tamsayı.değeri(str1).karşılaştırmak(Tamsayı.değeri(str2));    }};Koleksiyonlar.çeşit(liste, numStringComparator);

Java 8+ sürümünde bu şu şekilde yazılabilir:

Liste<Dize> liste = Diziler.asList("10", "1", "20", "11", "21", "12");		Karşılaştırıcı<Dize> numStringComparator = (str1, str2) -> Tamsayı.değeri(str1).karşılaştırmak(Tamsayı.değeri(str2));Koleksiyonlar.çeşit(liste, numStringComparator);

JavaScript'te

İçinde JavaScript fonksiyonlar birinci sınıf nesnelerdir. JavaScript ayrıca kapatmaları da destekler.

Aşağıdakileri sonraki Python örneğiyle karşılaştırın.

işlevi Akümülatör(Başlat) {  var akım = Başlat;  dönüş işlevi (x) {    dönüş akım += x;  };}

Bunun kullanımda bir örneği:

var a = Akümülatör(4);var x = a(5);   // x, 9 değerine sahiptirx = a(2);       // x 11 değerine sahiptirvar b = Akümülatör(42);x = b(7);       // x 49 değerine sahiptir (akım = 49 kapanışta)x = a(7);       // x 18 değerine sahiptir (a kapanışında akım = 18)

Julia'da

İçinde Julia yöntemler türlerle ilişkilidir, bu nedenle herhangi bir keyfi Julia nesnesini türüne yöntemler ekleyerek "çağrılabilir" yapmak mümkündür. (Bu tür "çağrılabilir" nesnelere bazen "functors" denir.)

Bir örnek bu akümülatör değiştirilebilir yapıdır ( Paul Graham's programlama dili sözdizimi ve netliği üzerine çalışma):[4]

Julia> değişebilir yapı Akümülatör           n::Int       sonJulia> işlevi (acc::Akümülatör)(n2)           acc.n += n2       sonJulia> a = Akümülatör(4)Akümülatör(4)Julia> a(5)9Julia> a(2)11Julia> b = Akümülatör(42)Akümülatör(42)Julia> b(7)49

Böyle bir akümülatör, kapatma kullanılarak da uygulanabilir:

Julia> işlevi Akümülatör(n0)           n = n0           işlevi(n2)               n += n2           son       sonAkümülatör (genel işlevi ile 1 yöntem)Julia> a = Akümülatör(4)(::# 1) (1 yöntemle genel işlev)Julia> a(5)9Julia> a(2)11Julia> b = Akümülatör(42)(::# 1) (1 yöntemle genel işlev)Julia> b(7)49

Lisp ve Scheme'de

Lisp aile dillerinde, örneğin Ortak Lisp, Şema ve diğerleri, işlevler tıpkı dizeler, vektörler, listeler ve sayılar gibi nesnelerdir. Bir kapatma oluşturma operatörü, bir işlev nesnesi programın bir bölümünden: operatöre argüman olarak verilen kod parçası, işlevin bir parçasıdır ve sözcüksel ortam da öyledir: sözcüksel olarak görünür değişkenlerin bağları yakalanan ve daha yaygın olarak a adı verilen işlev nesnesinde saklanır kapatma. Yakalanan bağlar şu rolü oynar: üye değişkenlerive kapanışın kod kısmı, anonim üye işlevi, C ++ 'daki operatör () gibi.

Kapanış yapıcısı sözdizimine sahiptir (lambda (parametreler ...) kodu ...). (parametreler ...) bölümü, bir arabirimin bildirilmesine izin verir, böylece işlev bildirilen parametreleri alır. kod ... bölüm, functor çağrıldığında değerlendirilen ifadelerden oluşur.

C ++ gibi dillerdeki birçok functor kullanımı, eksik kapatma yapıcısının basitçe öykünmeleridir. Programcı doğrudan bir kapanış oluşturamadığından, gerekli tüm durum değişkenlerine sahip bir sınıfı ve ayrıca bir üye işlevi tanımlaması gerekir. Ardından, bunun yerine bu sınıfın bir örneğini oluşturun ve tüm üye değişkenlerin yapıcısı aracılığıyla başlatıldığından emin olun. Değerler, doğrudan bir kapanış tarafından yakalanması gereken yerel değişkenlerden tam olarak türetilir.

Sınıf sistemini kullanan bir işlev nesnesi, kapatmalar kullanılmaz:

(defclass sayaç ()  ((değer : initarg : değer : erişimci değeri)))(defme yöntemi functor-call ((c sayaç))  (incf (değeri c)))(defun sayacı yapmak (başlangıç ​​değeri)  (örnek oluşturmak 'sayaç : değer başlangıç ​​değeri));;; sayacı kullanın:(defvar * c * (sayacı yapmak 10))(functor-call * c *) --> 11(functor-call * c *) --> 12

Lisp'te işlevsel nesneler yapmanın standart bir yolu olmadığından, bunu FUNCTOR-CALL adlı genel bir işlev tanımlayarak taklit ediyoruz. Bu, herhangi bir sınıf için özelleştirilebilir. Standart FUNCALL işlevi genel değildir; sadece fonksiyon nesnelerini alır.

Bize fonksiyon nesnelerini veren bu FUNCTOR-CALL jenerik fonksiyonudur. Bir nesnenin, genellikle aynı sözdizimiyle sıradan bir işlevmiş gibi çağrılmasına veya çağrılmasına izin veren bir bilgisayar programlama yapısı. Sahibiz neredeyse aynı sözdizimi: FUNCALL yerine FUNCTOR-CALL. Bazı Lisp'ler sağlar kullanılabilir basit bir uzantı olarak nesneler. İşlevlerle aynı sözdizimini kullanarak nesneleri çağrılabilir hale getirmek oldukça önemsiz bir iştir. Bir işlev çağrısı operatörünün farklı türlerde çalışması işlev şeyler, ister sınıf nesneleri ister kapanışlar olsun, tamsayılar, gerçekler veya karmaşık sayılar gibi farklı sayı türleriyle çalışan bir + işleci yapmaktan daha karmaşık değildir.

Şimdi, bir kapatma kullanılarak uygulanan bir sayaç. Bu çok daha kısa ve doğrudandır. SAYAÇ YAPININ BAŞLANGIÇ DEĞERİ argümanı fabrika işlevi doğrudan yakalanır ve kullanılır. Bir yapıcı aracılığıyla bazı yardımcı sınıf nesnelerine kopyalanması gerekmez. O dır-dir sayaç. Yardımcı bir nesne oluşturulur, ancak bu olur kamera ARKASI.

(defun sayacı yapmak (değer)  (lambda () (incf değer)));;; sayacı kullan(defvar * c * (sayacı yapmak 10))(funcall * c *) ; --> 11(funcall * c *) ; --> 12

Scheme, kapanışları daha da basitleştirir ve Scheme kodu, bu tür üst düzey programlamayı biraz daha deyimsel olarak kullanma eğilimindedir.

(tanımlamak (sayacı yapmak değer)  (lambda () (Ayarlamak! değer (+ değer 1)) değer));;; sayacı kullan(tanımlamak c (sayacı yapmak 10))(c) ; --> 11(c) ; --> 12

Aynı sözlü ortamda birden fazla kapanış oluşturulabilir. Her biri belirli bir tür işlem uygulayan bir kapanış vektörü, bir dizi sanal işlem içeren bir nesneyi oldukça sadık bir şekilde taklit edebilir. Bu tür tek gönderim nesne yönelimli programlama tamamen kapanışlarla yapılabilir.

Bu nedenle, meşhur dağın her iki tarafından kazılmış bir tür tünel vardır. OOP dillerindeki programcılar, nesnelerin bir tane sahip olmasını kısıtlayarak işlev nesnelerini keşfeder. ana işlevi yapmak o nesnenin işlevsel amacı ve hatta adını ortadan kaldırın, böylece nesne çağrılıyormuş gibi görünür! Kapakları kullanan programcılar, bir nesnenin bir işlev gibi adlandırılmasına şaşırmazken, aynı ortamı paylaşan birden çok kapağın, sanal bir tablo gibi eksiksiz bir soyut işlemler kümesi sağlayabileceğini keşfederler. tek gönderim OOP yazın.

Objective-C'de

İçinde Amaç-C, bir işlev nesnesi oluşturulabilir NSInvocation sınıf. Bir işlev nesnesinin oluşturulması bir yöntem imzası, hedef nesne ve hedef seçici gerektirir. Mevcut nesnenin çağrısına bir çağrı oluşturmak için bir örnek aşağıda verilmiştir. myMethod:

// Bir işlev nesnesi oluşturunSEL sel = @selector(myMethod);NSInvocation* inv = [NSInvocation invocationWithMethodSignature:                     [kendini methodSignatureForSelector:sel]];[inv hedef belirle:kendini];[inv setSelector:sel];// Gerçek çağrıyı yapın[inv çağırmak];

Bir avantajı NSInvocation hedef nesnenin oluşturulduktan sonra değiştirilebilmesidir. Bir tek NSInvocation yaratılabilir ve ardından herhangi bir sayıdaki hedefin her biri için, örneğin gözlemlenebilir bir nesneden çağrılabilir. Bir NSInvocation yalnızca bir protokolden oluşturulabilir, ancak bu basit değildir. Görmek İşte.

Perl'de

İçinde Perl, sınıfın oluşturucusundan, nesnenin örnek verileri üzerinde kapalı bir işlev döndüren, sınıfa kutsanan bir işlev nesnesi oluşturulabilir:

paket Acc1;alt yeni {    benim $ sınıf = vardiya;    benim $ arg = vardiya;    benim $ obj = alt {        benim $ num = vardiya;        $ arg += $ num;    };    kutsamak $ obj, $ sınıf;}1;

veya aşırı yükleyerek &{} işleci, böylece nesne bir işlev olarak kullanılabilir:

paket Acc2;kullanım aşırı yükleme    '&{}' =>        alt {            benim $ self = vardiya;            alt {                benim $ num = vardiya;                $ self->{arg} += $ num;            }        };alt yeni {    benim $ sınıf = vardiya;    benim $ arg = vardiya;    benim $ obj = { arg => $ arg };    kutsamak $ obj, $ sınıf;}1;

Her iki durumda da işlev nesnesi, başvuruyu kaldırma ok sözdizimi kullanılarak kullanılabilir. $ başvuru -> (@ bağımsız değişkenler):

kullanım Acc1;benim $ a = Acc1->yeni(42);Yazdır $ a->(10), " n";    # baskı 52Yazdır $ a->(8), " n";     # baskı 60

veya coderef dereferencing sözdizimini kullanarak & $ ref (@ argümanlar):

kullanım Acc2;benim $ a = Acc2->yeni(12);Yazdır &$ a(10), " n";     # baskı 22Yazdır &$ a(8), " n";      # baskı 30

PHP'de

PHP 5.3+ vardır birinci sınıf işlevler örneğin kullanılabilir usort () işlevinin parametresi olarak:

$ a = dizi(3, 1, 4);usort($ a, işlevi ($ x, y) { dönüş $ x - y; });

PHP 5.3+, lambda işlevlerini ve kapanmalarını da destekler.

işlevi Akümülatör($ başlangıç){    $ akım = $ başlangıç;    dönüş işlevi($ x) kullanım(&$ akım)    {        dönüş $ akım += $ x;    };}

Bunun kullanımda bir örneği:

$ a = Akümülatör(4);$ x = $ a(5);Eko "x = $ x
"
; // x = 9$ x = $ a(2);Eko "x = $ x
"
; // x = 11

PHP 5.3+ sürümünde nesneleri sınıflarına sihirli bir __invoke () yöntemi ekleyerek çağırılabilir yapmak da mümkündür:[5]

sınıf Eksi{    halka açık işlevi __çağırmak($ x, y)    {        dönüş $ x - y;    }}$ a = dizi(3, 1, 4);usort($ a, yeni Eksi());

PowerShell'de

İçinde Windows PowerShell dil, bir komut dosyası bloğu, tek bir birim olarak kullanılabilen ifadeler veya ifadeler koleksiyonudur. Bir betik bloğu bağımsız değişkenleri kabul edebilir ve değerleri döndürebilir. Komut dosyası bloğu, bir Microsoft .NET Framework System.Management.Automation.ScriptBlock yazın.

Fonksiyon Get-Accumulator($ x) {    {        param(y)        dönüş $ x += y    }.GetNewClosure()}
Not C: >$ a = Get-Accumulator 4Not C: >& $ a 59Not C: >& $ a 211Not C: >$ b = Get-Accumulator 32Not C: >& $ b 1042

Python'da

İçinde Python işlevler, tıpkı dizeler, sayılar, listeler vb. gibi birinci sınıf nesnelerdir. Bu özellik, birçok durumda bir işlev nesnesi yazma ihtiyacını ortadan kaldırır. İle herhangi bir nesne __telefon etmek__() yöntem işlev çağrısı sözdizimi kullanılarak çağrılabilir.

Bir örnek bu akümülatör sınıfıdır ( Paul Graham's programlama dili sözdizimi ve netliği üzerine çalışma):[6]

sınıf Akümülatör:    def __içinde__(kendini, n) -> Yok:        kendini.n = n    def __telefon etmek__(kendini, x):        kendini.n += x        dönüş kendini.n

Bunun kullanımda bir örneği (etkileşimli yorumlayıcı kullanılarak):

>>> a = Akümülatör(4)>>> a(5)9>>> a(2)11>>> b = Akümülatör(42)>>> b(7)49

Fonksiyonlar nesneler olduğundan, yerel olarak da tanımlanabilirler, nitelikler verilebilir ve diğer fonksiyonlar tarafından döndürülebilirler, [7] aşağıdaki örnekte gösterildiği gibi:

def Akümülatör(n):    def inc(x):        yerel olmayan n        n += x        dönüş n    dönüş inc

Ruby'de

İçinde Yakut çeşitli nesneler, özellikle Method ve Proc nesneleri olmak üzere işlev nesneleri olarak kabul edilebilir. Ruby ayrıca yarı işlevli nesneler olarak düşünülebilecek iki tür nesneye sahiptir: UnboundMethod ve block. UnboundMethods, bir işlev nesnesi olarak kullanılmadan önce bir nesneye bağlanmalıdır (böylece bir Yöntem haline gelir). Bloklar işlev nesneleri gibi adlandırılabilir, ancak başka herhangi bir kapasitede bir nesne olarak kullanılmak için (örneğin, bir argüman olarak iletilir) önce bir Proc'a dönüştürülmeleri gerekir. Daha yakın zamanlarda, semboller (gerçek tekli gösterge aracılığıyla erişilir :) ayrıca dönüştürülebilir Procs. Ruby'nin birliğini kullanma & operatör - aramaya eşdeğer to_proc bir nesne üzerinde ve yöntemin var olduğunu varsayarak - Ruby Uzantıları Projesi basit bir hack oluşturdu.

sınıf Sembol  def to_proc    proc { |obj, *argümanlar| obj.göndermek(kendini, *argümanlar) }  sonson

Şimdi, yöntem foo bir işlev nesnesi olabilir, yani bir Proc, üzerinden &: foo ve üzerinden kullanıldı take_a_functor (&: foo). Symbol.to_proc Ruby'ye resmi olarak 11 Haziran 2006'da RubyKaigi2006 sırasında eklendi. [1]

Formların çeşitliliği nedeniyle, Ruby'de Functor terimi genellikle bir Function nesnesi anlamında kullanılmaz. delegasyon tarafından tanıtıldı Ruby Yönleri proje Functor olarak adlandırılmıştır. En temel tanımı şudur:

sınıf Functor  def başlatmak(&işlev)    @func = işlev  son  def method_missing(op, *argümanlar, &blk)    @func.telefon etmek(op, *argümanlar, &blk)  sonson

Bu kullanım, işlevsel programlama dilleri tarafından kullanılana daha yakındır. ML ve orijinal matematiksel terminoloji.

Diğer anlamlar

Daha teorik bir bağlamda işlev nesnesi özellikle aşağıdaki gibi dillerde işlev sınıfının herhangi bir örneği olarak düşünülebilir Ortak Lisp hangi fonksiyonlar birinci sınıf nesneler.

ML ailesinin fonksiyonel programlama diller terimi kullanır functor temsil etmek haritalama modüllerden modüllere veya türlerden türlere ve kodu yeniden kullanmak için bir tekniktir. Bu şekilde kullanılan işlevler, orijinal matematiksel anlamı ile benzerdir. functor içinde kategori teorisi veya C ++, Java veya Java'da jenerik programlama kullanımına Ada.

İçinde Haskell terim, kategori teorisinde olduğu gibi kullanılır.

İçinde Prolog ve ilgili diller, functor eşanlamlıdır fonksiyon sembolü.

Ayrıca bakınız

Notlar

  1. ^ C ++ 'da bir işlevli bir ana yöntemi olan bir nesnedir ve functor bir functionoidin özel bir durumudur.[1] Bir işlev nesnesine benzerler, ama aynı değil.

Referanslar

  1. ^ Bir fonksiyonoid ve bir functor arasındaki fark nedir?
  2. ^ Silan Liu. "C ++ Eğitimi Bölüm I - Temel: 5.10 İşlev işaretçileri esas olarak geri arama tekniğini elde etmek için kullanılır ve bundan hemen sonra tartışılacaktır". TRIPOD: Programlama Eğitimleri Telif Hakkı © Silan Liu 2002. Alındı 2012-09-07. İşlev işaretçileri esas olarak, hemen sonra tartışılacak olan geri arama tekniğini elde etmek için kullanılır.
  3. ^ Paweł Turlejski (2009-10-02). "C ++ Eğitimi Bölüm I - Temel: 5.10 İşlev işaretçileri esas olarak geri arama tekniğini elde etmek için kullanılır ve bundan hemen sonra tartışılacaktır". Sadece Birkaç Satır. Alındı 2012-09-07. PHP 5.3, diğer birçok özellikle birlikte kapanışlar getirdi. Artık Ruby / Groovy / Scala / any_modern_language adamlarının yapabileceği tüm harika şeyleri nihayet yapabiliriz, değil mi? Yapabiliriz, ama muhtemelen yapmayacağız… İşte nedeni.
  4. ^ Akümülatör Jeneratörü
  5. ^ Sihirli Yöntemlerle İlgili PHP Belgeleri
  6. ^ Akümülatör Jeneratörü
  7. ^ Python başvuru kılavuzu - Fonksiyon tanımları

daha fazla okuma

  • David Vandevoorde ve Nicolai M Josuttis (2006). C ++ Şablonları: Tam Kılavuz, ISBN  0-201-73484-2: Özellikle, bölüm 22, işlev nesnelerine ayrılmıştır.

Dış bağlantılar