A számítógépes programozásban a névtelen függvény vagy anonim függvény olyan függvénydefiníció, amely nincs azonosítóhoz kötve. Az anonim függvények gyakran olyan argumentumok, amelyeket magasabb rendű függvényeknek adnak át, vagy egy magasabb rendű függvény eredményének létrehozására használják, amelynek vissza kell adnia egy függvényt. Ha egy függvényt csak egyszer vagy néhányszor kell meghívni, akkor egyszerűbb lehet névtelen (lambda) függvényt használni, mivel kevesebb kódot igényel, mint egy külön nevet adni neki. Az anonim függvények mindenütt jelen vannak a funkcionális programozási nyelvekben és más , első osztályú függvényekkel rendelkező nyelvekben, ahol ugyanazt a szerepet töltik be a függvénytípusnál, mint a literálok más adattípusoknál .
Az anonim függvények Alonzo Church munkásságából származnak, amikor 1936-ban, az elektronikus számítógépek előtt feltalálta a Lambda-kalkulust, amelyben minden funkció névtelen. Sok programozási nyelvben a névtelen függvényeket a lambda kulcsszóval hozzák létre, és ezeket gyakran egyszerűen lambdáknak vagy lambda absztrakcióknak nevezik. Az anonim függvények a Lisp 1958-as megjelenése óta a programozási nyelvek jellemzői, és egyre több modern programozási nyelv támogatja az anonim funkciókat.
Nevek A lambda absztrakció egy módja annak, hogy névtelen függvényeket írjunk le. A lambda-kalkulusban a λx.M kifejezés azt jelenti, hogy van egy függvényünk, amely bemeneti értékként x-et kap, és visszaadja az M kifezés eredményét. Ez hasonlít a Python lambda x: M szintaxisára, ahol szintén névtelen függvényeket lehet írni egy sorban.
A „nyílfüggvény” elnevezés a matematikai „ leképezi a ” szimbólumot, . Összehasonlítja az x => M JavaScript szintaxisával x => M.
Felhasználások Az anonim függvények használhatók olyan funkciók tárolására, amelyeket nem kell elnevezni, és esetleg rövid távú használatra. Néhány figyelemre méltó példa a bezárások és a currying .
Az anonim funkciók használata stílus kérdése. Használatuk soha nem az egyetlen módja a probléma megoldásának; ehelyett minden névtelen függvényt megnevezett függvényként definiálhatunk, és név szerint hívhatjuk meg. Az anonim függvények gyakran rövidebb jelölést adnak, mint az elnevezett függvények meghatározása. Azokon a nyelveken, amelyek nem teszik lehetővé a nevesített függvények helyi hatókörön belüli meghatározását, az anonim függvények beágyazást biztosíthatnak a lokalizált hatókörön keresztül, azonban az ilyen névtelen függvény törzsében lévő kód nem feltétlenül használható újra, vagy nem alkalmas külön tesztelésre. A kifejezésekben használt rövid/egyszerű névtelen függvények könnyebben olvashatók és megérthetők, mint a külön-külön definiált elnevezett függvények, bár leíró név nélkül nehezebb megérteni őket.
Egyes programozási nyelvekben az anonim függvényeket általában nagyon specifikus célokra valósítják meg, például események visszahívásokhoz vagy a függvények példányosításához bizonyos értékekhez, ami dinamikus programozási nyelvben hatékonyabb lehet, olvashatóbb és kevésbé hibás, mint egy elnevezett függvény meghívása.
A következő példák Python 3-ban vannak írva.
Osztályozás Ha nem szabványos módon próbál rendezni, könnyebb lehet a rendezési logikát névtelen függvényként tartalmazni, ahelyett, hogy megnevezett függvényt hozna létre. A legtöbb nyelv tartalmaz egy általános rendezési funkciót, amely olyan rendezési algoritmust valósít meg, amely tetszőleges objektumokat rendez. Ez a függvény általában elfogad egy tetszőleges függvényt, amely meghatározza, hogyan kell összehasonlítani, hogy két elem egyenlő-e, vagy az egyik nagyobb vagy kisebb, mint a másik.
Fontolja meg ezt a Python-kódot, amely a karakterláncok listáját a karakterlánc hossza szerint rendezi:>>> a = ['house', 'car', 'bike'] >>> a.sort(key=lambda x: len(x)) >>> a ['car', 'bike', 'house']Ebben a példában az anonim függvény a lambda kifejezés:lambda x: len(x)Az anonim függvény elfogad egy argumentumot, x, és visszaadja argumentuma hosszát, amelyet aztán a sort() metódus a rendezés kritériumaként használ.
A lambda függvény alapvető szintaxisa a Pythonban azlambda arg1, arg2, arg3, ...: <operation on the arguments returning a value>A lambda függvény által visszaadott kifejezés hozzárendelhető egy változóhoz, és több helyen is felhasználható a kódban.>>> add = lambda a: a + a >>> add(20) 40Egy másik példa az elemek rendezése egy listában az osztály neve alapján (Pythonban mindennek van osztálya):>>> a = [10, 'number', 11.2] >>> a.sort(key=lambda x: x.__class__.__name__) >>> a [11.2, 10, 'number']Vegye figyelembe, hogy 11.2 osztály neve " float ", a 10 osztály neve " int ", és 'number' osztály neve " str ". A rendezett sorrend: " float ", " int ", majd " str ".
Lezárások A lezárások kötött változókat tartalmazó környezetben kiértékelt függvények. A következő példa a "threshold" változót köti össze egy névtelen függvényben, amely összehasonlítja a bemenetet a küszöbértékkel.def comp(threshold): return lambda x: x < thresholdEz egyfajta összehasonlító függvény generátorként használható:>>> func_a = comp(10) >>> func_b = comp(20)
>>> print(func_a(5), func_a(8), func_a(13), func_a(21)) True True False False
>>> print(func_b(5), func_b(8), func_b(13), func_b(21)) True True True FalseNem lenne praktikus minden egyes összehasonlításhoz külön függvényt írni, ráadásul kényelmetlen lenne a küszöbértéket külön tárolni a későbbi felhasználáshoz. Függetlenül attól, hogy miért használják a lezárást, az anonim függvény az az entitás, amely tartalmazza az összehasonlítást végző funkcionalitást.
Currying A currying azt jelenti, hogy egy több bemenetet váró függvényt átalakítunk úgy, hogy egyszerre csak egy bemenetet fogadjon el, és minden egyes bemenetre egy újabb függvényt adjon vissza, amely a következő bemenetet várja. Ebben a példában egy tetszőleges egész számmal való osztást végrehajtó függvény olyan funkcióvá alakul, amely egy meghatározott egész számmal való osztást hajt végre.>>> def divide(x, y): ... return x / y
>>> def divisor(d): ... return lambda x: divide(x, d)
>>> half = divisor(2) >>> third = divisor(3)
>>> print(half(32), third(32)) 16.0 10.666666666666666
>>> print(half(40), third(40)) 20.0 13.333333333333334Bár az anonim függvényeket nem feltétlenül használják gyakran currying során, mégis jól alkalmazhatók erre is. A fenti példában a függvényosztó olyan függvényeket hoz létre, amelyek egy előre megadott osztóval osztanak. Így jönnek létre például a "felező" vagy "harmadoló" függvények, amelyek rögzített osztóval végzik az osztást.
Az osztófüggvény a d változó bekötésével is zárást képez.
Magasabb rendű funkciók A magasabb rendű függvény olyan függvény, amely egy függvényt argumentumként vesz fel, vagy eredményeként ad vissza egy függvényt. Ezt általában egy általánosan meghatározott függvény viselkedésének testreszabására használják, gyakran hurkolt konstrukciók vagy rekurziós sémák. Az anonim függvények egyszerű és kényelmes módot kínálnak arra, hogy függvényeket adjunk át argumentumként. Az alábbi példák Python 3-ban íródtak.
Térkép A leképező függvény végigmegy a lista elemein, és mindegyikre alkalmaz egy megadott függvényt. A következő példa egy tömb minden elemét négyzetre emeli egy névtelen függvénnyel.>>> a = [1, 2, 3, 4, 5, 6] >>> list(map(lambda x: x * x, a)) [1, 4, 9, 16, 25, 36]Az anonim függvény elfogad egy argumentumot, és önmagával megszorozza (négyezi). A nyelv készítői nem javasolják a fenti formátum használatát, mivel szerintük az alábbi változat ugyanazt jelenti, de jobban tükrözi a nyelv szemléletét és elveit. >>> a = [1, 2, 3, 4, 5, 6]>>> a = [1, 2, 3, 4, 5, 6] >>> [x * x for x in a] [1, 4, 9, 16, 25, 36]
Szűrő A szűrőfüggvény egy listából minden olyan elemet visszaad, amely egy bizonyos függvénynek való átadáskor igaz értéket ad.>>> a = [1, 2, 3, 4, 5, 6] >>> list(filter(lambda x: x % 2 == 0, a)) [2, 4, 6]Az anonim függvény ellenőrzi, hogy a neki átadott argumentum páros-e. Ugyanúgy, mint a térképnél, az alábbi űrlap megfelelőbbnek tekinthető:>>> a = [1, 2, 3, 4, 5, 6] >>> [x for x in a if x % 2 == 0] [2, 4, 6]
Hajtsa be A hajtási függvény végigfut a struktúra minden elemén (általában balról jobbra haladó listáknál a „bal oldali hajtás”, amelyet Pythonban reduce neveznek), és menet közben felhalmoz egy értéket. Ezzel a struktúra összes elemét egyetlen értékké lehet kombinálni, például:>>> from functools import reduce >>> a = [1, 2, 3, 4, 5] >>> reduce(lambda x, y: x * y, a) 120Ez megoldja
Az anonim függvény itt a két argumentum szorzata.
A hajtás eredményének nem kell egy értéknek lennie. Ehelyett a térkép és a szűrő is létrehozható hajtással. A térképen a felhalmozott érték egy új lista, amely egy függvény alkalmazásának eredményeit tartalmazza az eredeti lista minden elemére. A szűrőben a felhalmozott érték egy új lista, amely csak azokat az elemeket tartalmazza, amelyek megfelelnek az adott feltételnek.
Nyelvek listája Az alábbiakban felsoroljuk azokat a programozási nyelveket, amelyek teljes mértékben vagy részben támogatják a névtelen funkciókat valamilyen változatként, vagy egyáltalán nem.
Ez a táblázat néhány általános tendenciát mutat be. Először is, azok a nyelvek, amelyek nem támogatják az anonim függvényeket ( C, Pascal, Object Pascal ), mind statikusan beírt nyelvek. A statikusan beírt nyelvek azonban támogathatnak névtelen funkciókat. Például az ML nyelvek statikusan vannak beírva, és alapvetően névtelen függvényeket tartalmaznak, a Delphi pedig, az Object Pascal dialektusa, kibővült a névtelen funkciók támogatására, akárcsak a C++ (a C++11 szabvány szerint). Másodszor, a függvényeket első osztályú függvényként kezelő nyelvek ( Dylan, Haskell, JavaScript, Lisp, ML, Perl, Python, Ruby, Scheme ) általában anonim függvénytámogatással rendelkeznek, így a függvények ugyanolyan könnyen definiálhatók és továbbíthatók, mint más adattípusok. +Nyelvek listájaNyelvTámogatásMegjegyzésActionScript✗Ada✓Az 'expression functions' részei az Ada2012-nek, access-to-subprogram támogatássalALGOL 68✗APL✓Dyalog, ngn és dzaima APL támogatja a dfns-t és tacit függvényeket; GNU APL csak korlátozottanAssembly nyelvek✗AHK✓Az AutoHotkey V2 óta támogatott, JavaScripthez hasonló szintaxissalBash✓Könyvtár elérhető anonim függvények támogatásáraC✓Clang és LLVM compiler-rt támogatja; GCC makróval megoldhatóC#✓TámogatottC++✓C++11 szabvány óta támogatottCFML✓Railo 4 és ColdFusion 10 óta támogatottClojure✓COBOL✓A Micro Focus Managed COBOL támogatja (nem szabványos)Curl✗D✓Dart✓Delphi✓Dylan✓Eiffel✗Elm✓Elixir✓Erlang✓F#✓Excel✓2021 béta verzió óta támogatottFactor✓„Quotations” segítségével támogatottFortran✗Frink✓Go✓Gosu✓Groovy✓Haskell✓Haxe✓Java✓Java 8 óta támogatottJavaScript✓Julia✓Kotlin✓Lisp✓Logtalk✗Lua✓MUMPS✗Maple✓MATLAB✓Maxima✓Nim✓OCaml✓Octave✓Object Pascal✓Delphi 2009 óta támogatja, Oxygene dialektus isObjective-C (Mac OS X 10.6+)✓Blocks néven; C és C++ is támogatja Apple platformonOpenSCAD✓Function Literal támogatás 2021.01 ótaPascal✗Perl✓PHP✓PHP 5.3.0 óta valódi anonim függvényekPL/I✗Python✓lambda szintaxis – csak kifejezések, nem utasításokR✓Racket✓Raku✓Rexx✗RPG✗Ruby✓Blocks néven, Smalltalkból örökölveRust✓Scala✓Scheme✓Smalltalk✓Blocks névenStandard ML✓Swift✓Closures névenTypeScript✓Typst✓Tcl✓Vala✓Visual Basic .NET v9✓Visual Prolog v7.2✓Wolfram Language✓Zig✓
Hivatkozások
Lambda kalkulus eredete: Alonzo Church vezette be az 1930-as években, névtelen függvények pontos matematikai leírására. Forrás: Fernandez, Maribel (2009) – Models of Computation (Springer), 33. oldal. Magasabb rendű függvények és lambda-k a Haskell nyelvben: learnyouahaskell.com, clojure.org, cs.cornell.edu Lambda kifejezések különböző nyelvekben: Python: lambda x: x + 1 docs.python.org JavaScript: Nyílkifejezések: x => x + 1 developer.mozilla.org C#: x => x + 1 docs.microsoft.com F#: fun x -> x + 1 docs.microsoft.com