Currying ve parsiyel uygulama arasındaki fark nedir?


438

İnternette sık sık diğer insanların körüklenme örneklerinin körelmediği, ancak aslında sadece kısmi uygulama olduğuna dair çeşitli şikayetler görüyorum.

Kısmi uygulamanın ne olduğu veya körüklemeden nasıl farklı olduğuna dair iyi bir açıklama bulamadım. Genel bir karışıklık var gibi görünüyor, eşdeğer örnekler bazı yerlerde körleme, diğerlerinde kısmi uygulama olarak tanımlanıyor.

Birisi bana her iki terimin bir tanımını ve nasıl farklı olduklarının ayrıntılarını verebilir mi?

Yanıtlar:


256

Currying, n bağımsız değişkeninin tek bir işlevini, her biri tek bir bağımsız değişkenle n işlevine dönüştürüyor . Aşağıdaki işlev verildiğinde:

function f(x,y,z) { z(x(y));}

Kıvrıldığında, olur:

function f(x) { lambda(y) { lambda(z) { z(x(y)); } } }

F (x, y, z) 'nin tam uygulamasını elde etmek için bunu yapmanız gerekir:

f(x)(y)(z);

Birçok işlevsel dil yazmanıza izin verir f x y z. Yalnızca f x yveya f (x) (y) öğesini çağırırsanız , kısmen uygulanmış bir işleve sahip olursunuz; dönüş değeri, lambda(z){z(x(y))}x ve y değerlerini geçirerek kapatılır f(x,y).

Kısmi uygulamayı kullanmanın bir yolu, fonksiyonları fold gibi genelleştirilmiş fonksiyonların kısmi uygulamaları olarak tanımlamaktır :

function fold(combineFunction, accumulator, list) {/* ... */}
function sum     = curry(fold)(lambda(accum,e){e+accum}))(0);
function length  = curry(fold)(lambda(accum,_){1+accum})(empty-list);
function reverse = curry(fold)(lambda(accum,e){concat(e,accum)})(empty-list);

/* ... */
@list = [1, 2, 3, 4]
sum(list) //returns 10
@f = fold(lambda(accum,e){e+accum}) //f = lambda(accumulator,list) {/*...*/}
f(0,list) //returns 10
@g = f(0) //same as sum
g(list)  //returns 10

40
Kısmi uygulamanın bir işlevi köri yaptığınızda ve sonuçta ortaya çıkan işlevlerin tümünü değil bazılarını kullandığınızda olduğunu mu söylüyorsunuz?
SpoonMeiser

9
az çok evet. Yalnızca bağımsız değişkenlerin bir alt kümesini sağlarsanız, diğer bağımsız değişkenleri kabul eden bir işlevi geri alırsınız
Mark Cidade

1
F (a, b, c, d) işlevini g (a, b) olarak değiştirmek kısmi uygulama olarak sayılır mı? Yoksa sadece kavisli fonksiyonlara uygulandığında mı? Acı çektiğim için özür dilerim, ama burada açık bir cevap bekliyorum.
SpoonMeiser

2
@Mark: Sanırım bu, içimdeki bilgiçi ortaya çıkaran kavramlardan sadece biri - ama yetkili kaynaklara itiraz tatmin etmek için çok az şey yapıyor, çünkü hepsi birbirine işaret ediyor gibi görünüyor. Yetkili bir kaynak olarak düşündüğüm Wikipedia pek de zor değil, ama daha fazlasını bulmanın zor olduğunu anlıyorum. Yerel dillerin özellikleri üzerinde hemfikir olup olmadığımıza (veya katılmamaya bakılmaksızın) ikimiz de konuştuğumuzu ve gücünü bildiğimizi söylemek yeterli! :) Teşekkürler Mark!
Jason Bunting

5
@ JasonBunting, İlk yorumunuzla ilgili olarak, neden bahsettiğinizi telafi etmek . Currying, çoklu arg işlevini girdi olarak alıyor ve 1 arg işlevlerinin bir zincirini çıktı olarak döndürüyor. De-currying, 1-arg işlevlerinin bir zincirini girdi olarak alır ve çoklu arg işlevini çıktı olarak döndürür. Stackoverflow.com/a/23438430/632951
Pacerier

165

Nasıl farklı olduklarını görmenin en kolay yolu gerçek bir örnek düşünmektir . Diyelim ki Addgirdi olarak 2 sayı alan ve çıktı olarak bir sayı döndüren bir işleve sahibiz , örneğin Add(7, 5)döndürür 12. Bu durumda:

  • Fonksiyonu Addbir değerle kısmi olarak uygulamak7 bize çıktı olarak yeni bir fonksiyon verecektir. Bu fonksiyonun kendisi giriş olarak 1 sayı alır ve bir sayı verir. Gibi:

    Partial(Add, 7); // returns a function f2 as output
    
                     // f2 takes 1 number as input and returns a number as output
    

    Böylece bunu yapabiliriz:

    f2 = Partial(Add, 7);
    f2(5); // returns 12;
           // f2(7)(5) is just a syntactic shortcut
    
  • Currying fonksiyonu Addbize çıktı olarak yeni bir işlev verecektir. Bu işlev, kendi giriş ve çıkış olarak 1 sayısı alır henüz yeni bir fonksiyonu vardır. Bu üçüncü işlev daha sonra girdi olarak 1 sayı alır ve çıktı olarak bir sayı döndürür. Gibi:

    Curry(Add); // returns a function f2 as output
    
                // f2 takes 1 number as input and returns a function f3 as output
                // i.e. f2(number) = f3
    
                // f3 takes 1 number as input and returns a number as output
                // i.e. f3(number) = number
    

    Böylece bunu yapabiliriz:

    f2 = Curry(Add);
    f3 = f2(7);
    f3(5); // returns 12
    

Başka bir deyişle, "körelme" ve "kısmi uygulama" birbirinden tamamen farklı iki işlevdir. Körük tam olarak 1 girdi alırken, kısmi uygulama 2 (veya daha fazla) girdi alır.

Her ikisi de bir işlevi çıktı olarak döndürse de, döndürülen işlevler yukarıda gösterildiği gibi tamamen farklı biçimlerdedir.


24
Kısmi Uygulama bir işlevi dönüştürür n-aryiçin (x - n)-arygelen imalatı, n-aryiçin n * 1-ary. Kısmen uygulanan bir işlevin (uygulama) kapsamıAdd7 daha düşüktür , yani daha az ifadelidir Add. Öte yandan, curried bir işlev orijinal işlev kadar etkileyici.
bob

4
Ben daha belirgin özellik f (x, y, z) => R köri zaman, her biri tek bir argüman tüketen g (y) => h (z) => R döndüren f (x) olsun; ancak f (x, y, z) 'yi f (x) olarak kısmen uyguladığımızda g (y, z) => R, yani iki argümanla karşılaşırız. Bu özellik için değilse, körelemenin 0 argümana kısmi bir uygulama gibi olduğunu söyleyebiliriz, böylece tüm argümanları bağlı bırakabiliriz; ancak gerçekte f () kısmen 0 argümana uygulanır, curved f () 'in aksine bir kerede 3 argüman tüketen bir fonksiyondur.
Maksim Gumerov

2
Bir kez daha doğru cevap ilk ya da en çok oylanan değil: Bu cevabın sonunda kısmi ve kısmi imzanın basit açıklaması, sorunu çözmenin en kolay yoludur.
fnl

2
Yorum ne anlama f2(7)(5) is just a syntactic shortcutgeliyor? (Çok az şey biliyorum.) f2Zaten 7 içermiyor / bilmiyor mu?
Zach Mierzejewski

@Pacerier, bir curryyerde bir uygulama var mı (içinde olduğunu düşünmeyin functools)
alancalvitti

51

Not: Bu, F # Basics'ten işlevsel programlamaya giren .NET geliştiricileri için mükemmel bir tanıtım makalesi alındı .

Kıvrılma, birçok argümanlı bir işlevi, her birinin bir argüman alan ve sonuçta orijinal işlevle aynı sonucu veren bir dizi fonksiyona bölmesi anlamına gelir. Currying muhtemelen fonksiyonel programlamaya yeni başlayan geliştiriciler için en zor konudur, özellikle de kısmi uygulama ile karıştırılır. Bu örnekte her ikisini de iş yerinde görebilirsiniz:

let multiply x y = x * y    
let double = multiply 2
let ten = double 5

Hemen, çoğu zorunlu dilden farklı davranışlar görmelisiniz. İkinci ifade, iki bağımsız değişkene bir argüman ileterek double adlı yeni bir işlev oluşturur. Sonuç, bir int bağımsız değişkenini kabul eden ve x ile 2'ye çarpma ve bu bağımsız değişkene y ile çarpma çağrısıyla aynı çıktıyı veren bir işlevdir. Davranış açısından, bu kodla aynıdır:

let double2 z = multiply 2 z

Çoğu zaman, insanlar yanlışlıkla çoğaltmanın çift oluşturmak için kıvrıldığını söylerler. Ama bu sadece biraz doğru. Çarpma işlevi curried, ancak tanımlandığında gerçekleşir çünkü F #'daki işlevler varsayılan olarak curried. Çifte fonksiyon oluşturulduğunda, çarpma fonksiyonunun kısmen uygulandığını söylemek daha doğru olur.

Çarpma işlevi gerçekten iki işlevden oluşan bir seridir. İlk işlev bir int bağımsız değişkenini alır ve başka bir işlevi döndürerek x'i belirli bir değere etkin bir şekilde bağlar. Bu işlev ayrıca y'ye bağlanmak için değer olarak düşünebileceğiniz bir int bağımsız değişkenini de kabul eder. Bu ikinci işlevi çağırdıktan sonra, x ve y'nin her ikisi de bağlanır, dolayısıyla sonuç, çift gövdesinde tanımlandığı gibi x ve y'nin ürünüdür.

Çifte oluşturmak için, çarpma fonksiyonları zincirindeki ilk fonksiyon, çarpma işlemini kısmen uygulamak için değerlendirilir. Ortaya çıkan işleve double adı verilir. Çifte değerlendirildiğinde, sonucu oluşturmak için argümanını kısmen uygulanan değerle birlikte kullanır.


33

İlginç soru. Biraz arama yaptıktan sonra, "Kısmi İşlev Uygulaması körelmiyor" bulduğum en iyi açıklamayı verdi. Pratik farkın benim için özellikle açık olduğunu söyleyemem , ama o zaman bir FP uzmanı değilim ...

Başka bir kullanışlı görünümlü sayfa (henüz tam olarak okumadığımı itiraf ediyorum) "Java Kapakları ile Currying ve Kısmi Uygulama" dır .

Bu çok karışık terimler çifti gibi görünüyor, aklınızda olsun.


5
İlk bağlantı, farklılıklar hakkında açıktır. İşte yararlı bulduğum başka bir tane: bit.ly/CurryingVersusPartialApplication
Jason Bunting

5
Kurutma, tuples ile ilgilidir (bir grup bağımsız değişkenini alan bir işlevi n ayrı bağımsız değişken alan bir işleve dönüştürmek). Kısmi uygulama, bazı bağımsız değişkenlere bir işlev uygulama ve kalan bağımsız değişkenler için yeni bir işlev sağlama yeteneğidir. Tuples ile yapmak için == currying düşünüyorsanız düşünmek kolaydır.
Don Stewart

9
Yayınladığınız @Jon bağlantıları bilgilendiricidir, ancak cevabınızı genişletmek ve buraya biraz daha bilgi eklemek daha iyi olacaktır.
Zaheer Ahmed


11
Bir çift bağlantılar için 20 upvotes ve köri ve kısmi uygulama arasındaki farkı gerçekten bilmediğiniz bir giriş var inanamıyorum. İyi oynadın, efendim.
AlienWebguy

16

Bunu başka bir başlıkta cevapladım https://stackoverflow.com/a/12846865/1685865 . Kısacası, kısmi işlev uygulaması, çok değişkenli bir işlevin bazı argümanlarını daha az argümanla başka bir işlev verecek şekilde düzeltmekle ilgilidir; Currying, N argümanlarının bir işlevini, tekli bir işlev döndüren tekli bir işleve dönüştürmekle ilgilidir ... [Bir örnek Köri bu yazının sonunda gösterilir.]

Kurutma çoğunlukla teorik ilgi çekicidir: hesaplamalar yalnızca tekli fonksiyonları kullanarak ifade edilebilir (yani her fonksiyon tek). Pratikte ve bir yan ürün olarak, dilin fonksiyonlarının olması durumunda, birçok yararlı (ancak hepsi değil) kısmi fonksiyonel uygulamayı önemsiz hale getirebilen bir tekniktir. Yine, kısmi uygulamaları uygulamak için tek yol bu değildir. Böylece, kısmi uygulamanın başka bir şekilde yapıldığı senaryolarla karşılaşabilirsiniz, ancak insanlar bunu Currying olarak yanlış anlıyor.

(Körelme Örneği)

Pratikte kişi sadece yazmakla kalmaz

lambda x: lambda y: lambda z: x + y + z

veya eşdeğer javascript

function (x) { return function (y){ return function (z){ return x + y + z }}}

onun yerine

lambda x, y, z: x + y + z

Köriler uğruna.


1
Körelemenin özel bir kısmi uygulama örneği olduğunu söyleyebilir misiniz?
SpoonMeiser

1
@SpoonMeiser, Hayır, körelme özel bir kısmi uygulama örneği değildir: 2-girişli bir işlevin kısmi bir uygulaması, körükleme işlevi ile aynı değildir. Bkz. Stackoverflow.com/a/23438430/632951 .
Pacerier

10

Currying bir işlevidir tek bir işlevi alır argüman fve yeni bir fonksiyon verir h. Not hbir argüman alır Xve bir döndüren işlevi eşler Yiçin Z:

curry(f) = h 
f: (X x Y) -> Z 
h: X -> (Y -> Z)

Kısmi uygulama, bir işlevi alan ve yeni bir işleve bir veya daha fazla ek bağımsız değişken alan ve yeni bir işleve dönen iki (veya daha fazla) bağımsız fdeğişkenin fbir işlevidir g:

part(f, 2) = g
f: (X x Y) -> Z 
g: Y -> Z

Karışıklık, iki argüman işleviyle aşağıdaki eşitliğin geçerli olduğu için ortaya çıkar:

partial(f, a) = curry(f)(a)

Her iki taraf da aynı tek argüman işlevini verecektir.

Eşitlik, daha yüksek arity işlevleri için doğru değildir, çünkü bu durumda currying bir bağımsız değişken işlevi döndürürken, kısmi uygulama bir çoklu bağımsız değişken işlevi döndürür.

Fark, davranışta da bulunurken, köri, tüm orijinal işlevi özyinelemeli olarak dönüştürür (her argüman için bir kez), kısmi uygulama sadece bir adım yerine geçer.

Kaynak: Wikipedia Currying .


8

Köri ve kısmi uygulama arasındaki fark en iyi aşağıdaki JavaScript örneği ile gösterilebilir:

function f(x, y, z) {
    return x + y + z;
}

var partial = f.bind(null, 1);

6 === partial(2, 3);

Kısmi uygulama, daha küçük bir arena fonksiyonu ile sonuçlanır; Yukarıdaki örnekte, fise 3 arasında bir Arity sahip partialtek Daha da önemlisi 2 olabilen bir Arity sahip kısmen uygulanan fonksiyon olacaktır, çağırmak olmak üzerine hemen bir sonuç geri tımar zincirinde, başka bir fonksiyonu. Eğer böyle bir şey görüyorsanız partial(2)(3), gerçekte kısmi bir uygulama değildir.

Daha fazla okuma:


"kısmen uygulanan bir işlev çağrıldıktan hemen sonra sonucu döndürür" - bu doğru değil, değil mi? bir işlevi kısmen uyguladığımda, bu ifade "sonuç" değil, bir işlev döndürür. Tamam, muhtemelen bu ikinci fonksiyonun, kalan argümanlarla çağrıldığında, bir adım aşağıya inmenin aksine sonucu döndürdüğünü söylediniz. Ancak kimse aslında kalan tüm argümanları belirtmeniz gerektiğini söylemiyor: kısmi uygulamanın sonucunu kısmen uygulayabilirsiniz ve bu bir kez daha bir "sonuç" değil bir işlev olacaktır
Maksim Gumerov

6

Basit cevap

Curry: bir işlevi çağırmanıza ve birden çok çağrıya bölerek çağrı başına bir bağımsız değişken sunmanıza olanak tanır.

Kısmi: bir işlevi birden çok çağrıya bölerek her çağrı için birden çok bağımsız değişken sunmanızı sağlar.


Basit ipuçları

Her ikisi de daha az argüman sağlayan bir işlevi çağırmanıza izin verir (veya daha iyi, kümülatif olarak sağlar). Aslında her ikisi de (her çağrıda) işlevin belirli argümanlarına belirli bir değer bağlar.

Gerçek fark, işlevin 2'den fazla bağımsız değişkeni olduğunda görülebilir.


Basit e (c) (örnek)

(Javascript ile)

function process(context, success_callback, error_callback, subject) {...}

neden hep aynı olacaksa, neden bağlam ve geri çağrılar gibi argümanları her zaman iletiyoruz? Sadece fonksiyon için bazı değerleri bağlayın

processSubject = _.partial(process, my_context, my_success, my_error)

ve konu1 ve foobar ile

processSubject('subject1');
processSubject('foobar');

Rahat, değil mi? 😉

Currying ile her seferinde bir argüman geçmeniz gerekir

curriedProcess = _.curry(process);
processWithBoundedContext = curriedProcess(my_context);
processWithCallbacks = processWithBoundedContext(my_success)(my_error); // note: these are two sequential calls

result1 = processWithCallbacks('subject1');
// same as: process(my_context, my_success, my_error, 'subject1');
result2 = processWithCallbacks('foobar'); 
// same as: process(my_context, my_success, my_error, 'foobar');

feragat

Tüm akademik / matematiksel açıklamaları atladım. Çünkü bilmiyorum. Belki yardımcı oldu 🙃


4

Bu soruyu öğrenirken çok fazla soruyordum ve o zamandan beri birçok kez soruldum. Farkı tanımlamanın en basit yolu, her ikisinin de aynı olmasıdır :) Açıklayayım ... Açıkçası farklılıklar var.

Hem kısmi uygulama hem de körelme, bir işleve argümanların verilmesini içerir, belki de bir anda değil. Oldukça kanonik bir örnek iki sayı eklemektir. Sahte kodda (aslında anahtar kelimeler olmadan JS), temel işlev aşağıdaki olabilir:

add = (x, y) => x + y

Bir "addOne" işlevi istedim, kısmen uygulayabilir veya köri olabilir:

addOneC = curry(add, 1)
addOneP = partial(add, 1)

Şimdi bunları kullanmak açık:

addOneC(2) #=> 3
addOneP(2) #=> 3

Peki fark nedir? İnce, ancak kısmi uygulama bazı argümanlar sağlamayı içerir ve döndürülen işlev daha sonra bir sonraki çağrışımda ana işlevi yürütür, oysa köri gerekli tüm argümanlara sahip olana kadar beklemeye devam eder:

curriedAdd = curry(add) # notice, no args are provided
addOne = curriedAdd(1) # returns a function that can be used to provide the last argument
addOne(2) #=> returns 3, as we want

partialAdd = partial(add) # no args provided, but this still returns a function
addOne = partialAdd(1) # oops! can only use a partially applied function once, so now we're trying to add one to an undefined value (no second argument), and we get an error

Kısacası, bazı değerleri önceden doldurmak için kısmi uygulamayı kullanın, yöntemi bir sonraki çağırışınızda, yürütülür ve tanımlanmamış tüm bağımsız değişkenler bırakılır; işlev imzasını yerine getirmek için sürekli olarak kısmen uygulanmış bir işlevi gerektiği kadar döndürmek istediğinizde curried kullanın. Son bir örnek:

curriedAdd = curry(add)
curriedAdd()()()()()(1)(2) # ugly and dumb, but it works

partialAdd = partial(add)
partialAdd()()()()()(1)(2) # second invocation of those 7 calls fires it off with undefined parameters

Bu yardımcı olur umarım!

GÜNCELLEME: Bazı diller veya lib uygulamaları, iki tanımımı kafa karıştırıcı bir karmaşaya dönüştürebilecek kısmi uygulama uygulamasına bir pasiflik (son değerlendirmede toplam argüman sayısı) geçirmenize izin verecektir ... ancak bu noktada, iki teknik büyük ölçüde değiştirilebilir.


3

Benim için kısmi uygulama kullanılan argümanların sonuçlanan fonksiyona tamamen entegre olduğu yeni bir fonksiyon yaratmalıdır.

Çoğu fonksiyonel dil, bir kapama döndürerek köri uygular: kısmen uygulandığında lambda altında değerlendirme yapmayın. Bu nedenle, kısmi uygulamanın ilginç olması için, körelme ile kısmi uygulama arasında bir fark yaratmamız ve kısmi uygulamayı lambda altında körleme artı değerlendirme olarak düşünmemiz gerekir.


3

Burada çok yanlış olabilirim, çünkü teorik matematik veya fonksiyonel programlama konusunda güçlü bir arka planım yok, ancak kısa bir aramayla FP'ye girerken, körükleme N argümanlarının bir fonksiyonunu bir argümanın N fonksiyonlarına dönüştürme eğilimindedir, oysa kısmi uygulama [pratikte] belirsiz sayıda argümanla değişken işlevlerle daha iyi çalışır. Önceki cevaplardaki bazı örneklerin bu açıklamaya meydan okuduğunu biliyorum, ancak kavramları ayırmamda bana en çok yardımcı oldu. Bu örneği düşünün (özlü olma için CoffeeScript'te yazılmıştır, daha fazla kafa karıştırırsa özür dilerim, ancak gerekirse açıklık isteyin):

# partial application
partial_apply = (func) ->
  args = [].slice.call arguments, 1
  -> func.apply null, args.concat [].slice.call arguments

sum_variadic = -> [].reduce.call arguments, (acc, num) -> acc + num

add_to_7_and_5 = partial_apply sum_variadic, 7, 5

add_to_7_and_5 10 # returns 22
add_to_7_and_5 10, 11, 12 # returns 45

# currying
curry = (func) ->
  num_args = func.length
  helper = (prev) ->
    ->
      args = prev.concat [].slice.call arguments
      return if args.length < num_args then helper args else func.apply null, args
  helper []

sum_of_three = (x, y, z) -> x + y + z
curried_sum_of_three = curry sum_of_three
curried_sum_of_three 4 # returns a function expecting more arguments
curried_sum_of_three(4)(5) # still returns a function expecting more arguments
curried_sum_of_three(4)(5)(6) # returns 15
curried_sum_of_three 4, 5, 6 # returns 15

Bu açık bir şekilde çelişkili bir örnektir, ancak herhangi bir sayıda argümanı kabul eden bir fonksiyonun kısmen uygulanmasının bir fonksiyonu yerine getirmemize izin verdiğini ancak bazı ön verilerle dikkat çektiğini unutmayın. Bir fonksiyonun kurutulması benzerdir, ancak bir N-parametresi fonksiyonunu parçalar halinde yürütmemize izin verir, ancak sadece tüm N parametreleri hesaplanana kadar.

Yine, bu benim okuduğum şeylerden aldığım şey. Birisi aynı fikirde değilse, derhal bir düşüşten ziyade neden olduğu hakkında bir yorum için teşekkür ederiz. Ayrıca, CoffeeScript'in okunması zorsa, lütfen coffeescript.org adresini ziyaret edin, "coffeescript'i deneyin" i tıklayın ve derlenmiş sürümü görmek için kodumu yapıştırın (umarım) daha anlamlı olabilir. Teşekkürler!


2

Bu soruyu soran çoğu insanın temel kavramlara zaten aşina olduğunu varsayacağım, bu yüzden bunun hakkında konuşmaya gerek yok. Kafa karıştırıcı olan örtüşme.

Kavramları tam olarak kullanabiliyor olabilirsiniz, ancak onları bu sözde atomik amorf kavramsal bulanıklık olarak birlikte anlıyorsunuz. Eksik olan, aralarındaki sınırın nerede olduğunu bilmek.

Her birinin ne olduğunu tanımlamak yerine, sadece farklılıklarını vurgulamak daha kolaydır - sınır.

Currying ne zaman olduğunu tanımlamak fonksiyonu.

Kısmi Uygulama ne zaman olduğunu diyoruz işlevi.

Uygulama bir işlevi çağırmak için matematik konuşur.

Kısmi uygulama, curried bir işlevi çağırmayı ve dönüş türü olarak bir işlevi almayı gerektirir.


1

Burada başka harika cevaplar var, ancak Java'daki bu örneğin (anlayışım gereği) bazı insanlar için yararlı olabileceğine inanıyorum:

public static <A,B,X> Function< B, X > partiallyApply( BiFunction< A, B, X > aBiFunction, A aValue ){
    return b -> aBiFunction.apply( aValue, b );
}

public static <A,X> Supplier< X > partiallyApply( Function< A, X > aFunction, A aValue ){
    return () -> aFunction.apply( aValue );
}

public static <A,B,X> Function<  A, Function< B, X >  > curry( BiFunction< A, B, X > bif ){
    return a -> partiallyApply( bif, a );
}

Bu nedenle currying size kısmi uygulamanın bir veya daha fazla argümanı kodlayan bir sarmalayıcı işlevi oluşturduğu işlevler oluşturmak için bir bağımsız değişken işlevi sağlar.

Kopyalamak ve yapıştırmak istiyorsanız, aşağıdakiler daha gürültülüdür, ancak türleri daha yumuşak olduğu için çalışmak daha dostudur:

public static <A,B,X> Function< ? super B, ? extends X > partiallyApply( final BiFunction< ? super A, ? super B, X > aBiFunction, final A aValue ){
    return b -> aBiFunction.apply( aValue, b );
}

public static <A,X> Supplier< ? extends X > partiallyApply( final Function< ? super A, X > aFunction, final A aValue ){
    return () -> aFunction.apply( aValue );
}

public static <A,B,X> Function<  ? super A,  Function< ? super B, ? extends X >  > curry( final BiFunction< ? super A, ? super B, ? extends X > bif ){
    return a -> partiallyApply( bif, a );
}

Aşağıdakiler bana temel anlayışı verdi: "Yani körelme size fonksiyonlar yaratmanız için tek argümanlı bir fonksiyon veriyor, burada kısmi uygulama bir veya daha fazla argümanı kodlayan bir sarmalayıcı fonksiyonu yaratıyor."
Roland

0

Bunu yazarken, körelmeyi ve körelemeyi karıştırdım. Fonksiyonlar üzerinde ters dönüşümlerdir. Dönüşümün ve tersinin neyi temsil ettiği sürece, ne dediğiniz gerçekten önemli değil.

Telaşsızlık çok açık bir şekilde tanımlanmamıştır (ya da daha doğrusu, herkes fikrin ruhunu yakalayan "çelişkili" tanımlar). Temel olarak, birden fazla argümanı alan bir fonksiyonu tek bir argüman alan bir fonksiyona dönüştürmek anlamına gelir. Örneğin,

(+) :: Int -> Int -> Int

Şimdi, bunu tek bir argüman alan bir işleve nasıl dönüştürebilirsiniz? Elbette hile yapıyorsun!

plus :: (Int, Int) -> Int

Artı şimdi tek bir argüman alır (iki şeyden oluşur). Süper!

Bunun amacı ne? İki argüman alan bir fonksiyonunuz varsa ve bir çift argümanınız varsa, fonksiyonu argümanlara uygulayabileceğinizi ve yine de beklediğinizi elde edebileceğinizi bilmek güzel. Ve aslında, bunu yapmak için sıhhi tesisat zaten var, böylece açık desen eşleştirme gibi şeyler yapmak zorunda değilsiniz. Tüm yapman gereken:

(uncurry (+)) (1,2)

Peki kısmi fonksiyon uygulaması nedir? İki bağımsız değişkendeki bir işlevi tek bağımsız değişkenli bir işleve dönüştürmenin farklı bir yoludur. Yine de farklı çalışır. Yine, örnek olarak (+) örneğini ele alalım. Bunu nasıl tek bir Int'yi argüman olarak alan bir işleve dönüştürebiliriz? Hile yapıyoruz!

((+) 0) :: Int -> Int

Bu, herhangi bir Int.

((+) 1) :: Int -> Int

herhangi bir Int. Vb Bu vakaların her birinde, (+) "kısmen uygulanır".

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.