Remove ads
From Wikipedia, the free encyclopedia
У програмирању, композиција функција представља акт или механизам за комбиновање више једноставних функција ради стварања сложеније функције. Уобичајено је да се резултат сваке фунцкије преноси као аргумент следеће, а резултат последње је резултат целине.
Програмери често примењују функције на резултате неких других функција што допуштају готово сви програмски језици. У неким случајевима композиција функција је занимљива сама по себи као функција.Таква функција се увек може дефинисати, али језици са првокласним функцијама то олакшавају.
Могућност једноставне композиције функција подстиче рефакторисање функција за одржавање и поновну употребу кода. Генерално, велики системи се могу правити композицијом читавих програма.
Једноставно речено, композиција функција се односи на функције које раде на ограниченој количини података, сваки корак их узастопно обрађује пре него што пошаље следећем. Функције које обрађују бесконачно података познате су као филтри и повезане су у цевовод (pipeline), што је аналогно композицији функција и може се истовремено извршити.
На пример, претпоставимо да имамо две функције f и g, у облику z=f(y) и y=g(x). Њихова композиција подразмева прво израчунавање y=g(x) , а затим коришћење тог y за израчунавање z=f(y) . Следи пример у програмском језику C :
float x, y, z;
// ...
y = g(x);
z = f(y);
Кораци се могу комбиновати ако не задамо име средњем резултату:
z = f(g(x));
Упркос разликама у дужини, ове две имплементације дају исти резултат. Друга имплементација садржи само једну линију кода и назива се "highly composed" образац. Читљивост, а самим тим одрживост је једна од предности високо сређених облика, јер захтевају мање линија кода, минимизирајући ,,површину програма". [1]DeMarco и Lister емпиријски потврђују обрнут однос између површине и одржања.[2] С друге стране, високо компоновани облици могу бити претерани. Коришћење превише функција може имати супротан ефекат, чинећи код мање одрживим. У језицима који користе стек композиција функције је још природннија : изводи се спајањем и обично је примарна метода код дизајнирања програма.Следи пример у програмском језику Forth :
g f
Ово ће узети све што је било на стеку раније, применити g, затим f, и оставити резултат на стеку.
Сада претпоставимо да је комбинација позивања f() на резултат g() је често корисна и желимо је назвати foo() да би се могла користити као функција сама по себи .
У већини програмских језика, можемо дефинисати нову имплементирану преко композиције. Пример у C- у:
float foo(float x) {
return f(g(x));
}
Пример у Forth :
: foo g f ;
У програмском језику C једини начин да се креира нова функција је дефинисање исте у изворном коду, што значи да не могу бити додате док је програм покренут. Међутим, могућа је процена произвољне композиције унапред дефинисаних функција:
#include <stdio.h>
typedef int FXN(int);
int f(int x) { return x+1; }
int g(int x) { return x*2; }
int h(int x) { return x-3; }
int eval(FXN *fs[], int size, int x)
{
for (int i=0; i<size; i++) x = (*fs[i])(x);
return x;
}
int main()
{
// ((6+1)*2)-3 = 11
FXN *arr[] = {f,g,h};
printf("%d\n", eval(arr, 3, 6));
// ((6-3)*2)+1 = 7
arr[2] = f; arr[0] = h;
printf("%d\n", eval(arr, 3, 6));
}
У функционалним програмским језицима, композиција функција може се природно изразити као функција вишег реда или оператор. У другим програмским језицима може се написати сопствени механизам за извођење композиције функција.
У програмском језику Haskell , горенаведени пример постаје :
foo = f . g
коришћењем уграђеног оператора композиције (.), који се може читати као f након g или g састављен са f . Сам оператор композиције се може дефинисати у Haskell помођу ламбда израза (рачуна):
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
Haskell не захтева спецификацију конкретних типова улаза и излаза f и g, само односе између њих (f мора прихватити оно што g враћа). Овим (.) постаје полиморфни оператор.
Варијанте Lisp-а посебно Scheme , замењивост кода и података, заједно са третманом функција, дају се изузетно добро за рекурзивну дефиницију варијабилног композиционог оператора.
(define (compose . fs)
(if (null? fs) (lambda (x) x) ; ако није дат аргумент процењује се као функција идентитета
(lambda (x) ((car fs) ((apply compose (cdr fs)) x)))))
; примери
(define (add-a-bang str)
(string-append str "!"))
(define givebang
(compose string->symbol add-a-bang symbol->string))
(givebang 'set) ; ===> set!
;анонимна композиција
((compose sqrt negate square) 5) ; ===> 0+5i
Многи дијалекти APL-а имају уграђену функцијску композицију, која се користи као симбол ∘. Ова функција вишег реда проширује састав функције на дијадичну примену функције леве стране тако да A f∘g B
је A f g B
.
foo←f∘g
Поред тога може се дефинисати композиција функције:
o←{⍺⍺ ⍵⍵ ⍵}
У дијалекту који не подржава инлине дефиницију помоћу заграде, доступна је традиционална дефиниција:
∇ r←(f o g)x
r←f g x
∇
Попут Haskell-а, Raku има уграђен оператор композиције функција, главна разлика је у томе што се представља као ∘ или о.
my &foo = &f ∘ &g;
У наставку је Raku код који се користи да се дефинише оператор у Rakudo имплементацији.
proto sub infix:<∘> (&?, &?) is equiv(&[~]) is assoc<left> {*}
multi sub infix:<∘> () { *.self } # омогућава да `[∘] @array` ради када је `@array`празан
multi sub infix:<∘> (&f) { &f } # омогућава да `[∘] @array`ради када `@array`има један елементt
multi sub infix:<∘> (&f, &g --> Block) {
(&f).count > 1
?? -> |args { f |g |args }
!! -> |args { f g |args }
}
my &infix:<o> := &infix:<∘>;
У Python-у се композиција функције дефинише коришћењем reduce функције (functools.reduce у Python 3) :
# Доступно од верзије Python v2.6
from functools import reduce
def compose(*funcs) -> int:
"""Састављање групе композиција (f(g(h(...)))) у једну композитну функцију"""
return reduce(lambda f, g: lambda x: f(g(x)), funcs)
# Примери
f = lambda x: x + 1
g = lambda x: x * 2
h = lambda x: x - 3
# Позивање функције x=10 : ((x-3)*2)+1 = 15
print(compose(f, g, h)(10))
У овом програмском језику може се дефинисати као функција која узима две функције f и g и тако прави нову функцију:
function o(f, g) {
return function(x) {
return f(g(x));
}
}
// Коришћење осталих оператора и ламбда израза у ES2015
const compose = (...fs) => (x) => fs.reduceRight((acc, f) => f(acc), x)
У програмском језику C# се може дефинисати помоћу Func :
// Пример позива:
// var c = Compose(f, g);
//
// Func<int, bool> g = _ => ...
// Func<bool, string> f = _ => ...
Func<TIn, TOut> Compose<TIn, TMid, TOut>(Func<TMid, TOut> f, Func<TIn, TMid> g) => _ => f(g(_));
Језици попут језика Ruby-а омогућавају самостално прављење бинарног оператера:
class Proc
def compose(other_fn)
->(*as) { other_fn.call(call(*as)) }
end
alias_method :+, :compose
end
f = ->(x) { x * 2 }
g = ->(x) { x ** 3 }
(f + g).call(12) # => 13824
Међутим, сопствени оператор композиције функције уведен је у Ruby 2.6 :[3]
f = proc{|x| x + 2}
g = proc{|x| x * 3}
(f << g).call(3) # -> 11; идентично f(g(3))
(f >> g).call(3) # -> 15; идентично g(f(3))
Појмови композиције, укључујући принцип композиционости и компостибилности, су толико свеприсутни да су се бројне теме истраживања одвојено развијале.Следе узорковања врсте истраживања у којима је појам композиције централни.
Читави програми или системи могу се третирати као функције, које се лако могу саставити ако су њихови улази и излази добро дефинисани,[4] цевоводи омогућавају лако састављање филтера, па је све то постало дизајнерски образац оперативних система.
Императивни поступци са спољним ефектима крше референтну транспарентност и због тога се не могу чисто саставити. Међутим, ако узимате у обзир „стање света“ пре и после покретања кода као његове улазе и излазе, добићете чисту функцију. Састав таквих функција одговара покретању процедура једне за другом . Монадски формализам користи ову идеју да уврсти нуспојаве и И / О у функционалне језике.
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.