Bana biraz köri yap


20

X 1 , x 2 ,…, x n bağımsız değişkenlerini alan bir f işlevine sahip olmak

                                               - yani.  f: X 1 × X 2 ×… × X n → Y

- currying yeniden tanımlar f bir fonksiyonu olarak tek bir argüman alarak bir 1 daha başka bir işleve eşleştirir. Bu teknik, örneğin powyazabileceğimiz kavisli bir işlevle kısmi uygulama için yararlıdır exp = pow(e).

Misal

Aşağıdaki f işlevini üç argümanla ele aldığımızı varsayarsak ( f: X 1 × X 2 × X 3 → Y ):

def f(a,b,c):
  return a + b * c

Bu işlevi kürlemek bizi f_curry ile bırakır: X 1 → (X 2 → (X 3 → Y)) , eğer şimdi bu işlevi iki kez çağırırsak , aşağıdakine eşdeğer f_curry(1)(2)bir işlev ( h) elde ederiz :

def h(c):
   return 1 + 2 * c

Curried işlevi fşu şekilde yazılabilir (Python 3):

def f_curry(a):
  def g_curry(b):
    def h(c):
      return a + b * c
    return h
  return g_curry

Çevrimiçi deneyin!

Meydan okuma

Zorluğunuz yukarıda açıklandığı gibi bir işlevi körüklemek olacaktır, işte kurallar:

  • Giriş, en az 2 bağımsız değişken alan bir kara kutu işlevi olacaktır
  • Giriş işlevi her zaman sabit sayıda argümana sahip olacaktır (aksine printf ya da benzer, not: herhangi bir sayıda bağımsız değişkeni olan işlevleri desteklemeniz gerekir ≥2)
  • Dilinizde varsayılan olarak curried işlevler kullanılıyorsa (örn. Haskell), giriş işlevinin "üst düzey işlev" yerine N- kümeleri üzerinde tanımlanmasını bekleyebilirsiniz.
  • Bağımsız değişken sayısını girdi olarak alabilirsiniz
  • Çıktı, girdinin curried eşdeğeri olacaktır *
  • Çıktı işlevinin yalnızca şu şekilde olacağını varsayabilirsiniz:
    • giriş işlevinin aldığı bağımsız değişken sayısına eşit veya daha az olarak çağrıldı
    • doğru türde argümanlar ile çağrıldı

* Bu f, Nbağımsız değişkenleri olan bir girdi ve hgeçerli tüm bağımsız değişkenler için geçerli olan bir çıktı anlamına a1,…,aNgelir f(a1,a2,…,aN) == h(a1)(a2)…(aN).



böylece giriş def f(a,b,c): return a + b * cve çıkış def f_curry(a): def g_curry(b): def h(c): return a + b * c return h return g_curry?
DanielIndie

@DanielIndie: Bu örneği alıyorsanız, girdi f(bir yerde tanımlanır) olur ve çıktı buna eşdeğer bir şey olmalıdır f_curry. Veya girdi olur lambda a,b,c: a+b*cve çıktı eşdeğer bir fonksiyon olur f_curry.
ბიმო

Çoğu statik olarak yazılan dilde bunu yapmak zordur ... Sanırım bunun için tür işlevlerine ihtiyacınız var.
Paŭlo Ebermann

@ PaŭloEbermann: Doğru, bazı diller bu görevi çözemez ( işlevsel-programlama etiketine dikkat edin ). Bununla birlikte, statik olarak yazılan bazı diller geçerli bir G / Ç olabilecek işlev işaretçileri kullanabilir, bu da temel olarak argüman sayısını ek girdi olarak almamıza izin vermemin nedenidir.
ბიმო

Yanıtlar:


11

JavaScript (ES6), 35 bayt

f=g=>g.length<2?g:a=>f(g.bind(f,a))

9

Idris , 204 bayt

import Data.HVect
C:(a:Vect n Type)->(HVect a->Type)->Type
C[]T=T[]
C(h::t)T=(x:h)->C t(T .(x::))
c:{a:Vect n Type}->{T:HVect a->Type}->((b:HVect a)->T b)->C a T
c{a=[]}f=f[]
c{a=h::t}f=\v=>c(\u=>f(v::u))

Çevrimiçi deneyin!

Bağımlı tipler için bir iş gibi geliyor! Pekala belki.


C bir köri tipi fonksiyonudur. A = [t 1 , t 2 ,… t n ] tipinde bir vektör ve bir tip fonksiyonu verildiğinde T: HVect a → Tür yeni bir tür döndürür:

           (x 1  : t 1 ) → (x 2  : t 2 ) →… → (T [x 1 , x 2 ,… x n ])

Burada, HVect olan heterojen vektör tipi tipi - İdris Prelude gelen n -tuples, elemanları vardır n farklı türleri.

c alan bir fonksiyonu olan bir ve T örtülü bir bağımsız değişken olarak ve daha sonra dönüştürür uncurried fonksiyonu fÇeşidi : (HVect a) → Tb (b) ' a doğru curried tipi bir C T .

( C basitçe ne yapmak istediğimizi tanımlar; c aslında yapar. Ama Idris her üst düzey tanımın bir tür imzası olmasını talep ettiği için C'yi tanımlamaktan kurtulamayız .)


TIO bağlantısı bir kullanım örneği verir. 3-tuples (Nat, Nat, String) üzerinde aşağıdaki gibi bir işlev tanımlarsak :

uncurried : HVect [Nat, Nat, String] -> String
uncurried [a, b, c] = show (a*a + b*b) ++ c

sonra uncurried [3, 4, "th"]ile aynı sonucu verir c uncurried 3 4 "th". İdris argümanları ihlal ediyor a=[Nat, Nat, String]ve T=const Stringbizim için inanıyorum.

Ben bu kodu timjb tarafından bu gist dayalı.


Bence, Haskell ve İdris'in de küpe aslında olmalıdır HVectdefault- tarafından HVectsize uncons can bu tuple aslında.
Esolanging Fruit


5

R , 96 bayt

y=function(f,n=length(formals(f)),p=list())function(x,u=c(p,x))`if`(n<2,do.call(f,u),y(f,n-1,u))

Çevrimiçi deneyin!


Önceki sürüm (97 bayt)

@JayCE sayesinde -1 bayt


Temel olarak nasıl kısaltacağımı görmüyorum . Parantezlerden ve ilk satırın sonundaki boşluktan kurtularak üç bayt golf oynayabilirsiniz. Ve iki konvansiyondan dolayı, bayt sayısına işlevin adını dahil etmeme nedeniyle. TIO
ngm

@ngm İşlev adı özyinelemeli olduğunda dahil edilmelidir.
Ørjan Johansen

@ngm: if ifadesini onda biri byte tasarruf eden alt fonksiyonun içine koydum :)
digEmAll


3

Python 2 , 60 bayt

c=lambda f,n,l=[]:lambda a:n-1and c(f,n-1,l+[a])or f(*l+[a])

Çevrimiçi deneyin!

Altbilgi, STDIN'i satır başına aşağıdaki şekilde kullanan bir test kullanıcısıdır:

  1. Fonksiyonun kendisi
  2. İşlevin bağımsız değişkenlerinin sayısı, ≥2
  3. Bağımsız değişkenlerin bir listesi ( [a,b,...])

Bağımsız değişkenlerin bir listesi test cihazında girdi olarak verilirken, gerçekte, curried eşdeğeri listeye eklenir ve listenin işlev çağrısı ile azaltılır.

Benzer bir 55 baytlık sürüm ovs tarafından nazikçe sağlanmıştır :

c=lambda f,n,*l:lambda a:n-1and c(f,n-1,*l,a)or f(*l,a)

Çevrimiçi deneyin!


2

Karnabahar , 84 bayt

(:= c(\($f$n(@a))(if$n(\($a)(call c(cat(list$f(-$n 1))@a(list$a))))else(call$f@a))))

Çevrimiçi deneyin!


1
Mmm, Karnabahar köri. Lezzetli. ^ _ ^
DLosc

@DLosc, gıda ile ilgili isimlerle dillerde bu zorluğa yeterli cevap yok: P (bunların çoğunun aslında işlevleri yok olmasına rağmen)
ASCII-sadece



1

Ataşman , 5 bayt

Curry

Çevrimiçi deneyin!

Basit yerleşik, büyük ölçüde ilgisiz. Ancak, sıfırdan bir sürüm:

Ataşesi, 35 bayt

{If[#__2<#_,Fold[`&:,$'__],_@@__2]}

Açıklama:

{If[#__2<#_,Fold[`&:,$'__],_@@__2]}
{                                 }    lambda
 If[       ,              ,      ]     if
    #__2                                 the number of parameters after the first
        <#_                              is less than the arity of the first
            Fold[   ,    ]             then fold:
                 `&:                     right-function bonding
                     $                     over this function
                      '__                  paired with the rest of the parameters
                          ,            otherwise:
                           _@@           call the first parameter
                              __2        with the rest of them

1

Java 8, 46 + 318 = 364 bayt

Bu, bir işlevi ve bir argüman sayısını alan ve curried işlevi döndüren bir curried (hah) lambdadır.

import java.lang.reflect.*;import java.util.*;

f->p->new java.util.function.Function(){Object F=f;Method m=F.getClass().getDeclaredMethods()[0];int P=p;List a=new Stack();public Object apply(Object r){a.add(r);try{return a.size()<P?this:m.invoke(F,a.toArray());}catch(Throwable t){t=t.getCause();if(t instanceof Error)throw(Error)t;else throw(RuntimeException)t;}}}

Çevrimiçi Deneyin

Gönderme türü

Giriş işlevi

İşlev girdisi, işlevi temsil eden tek bir yönteme (devralınan yöntemler hariç) bir nesnedir. Standart bir fonksiyonel arayüzün giriş tipi olarak kullanılamayacağına dikkat edin, çünkü (3 gibi) parametrelerin işlevleri desteklenmelidir. Ayrıca, standart java.util.function.Functionbenzeri bir türe dökülen lambda ifadesinin geçirilebileceğini unutmayın (tek yöntemapply ).

İşaretli istisnalar giriş işlevinde bildirilebilir, ancak bunlar atılamaz (yani, çıkış işlevinin çağırana yayılmaz). Java'nın işlevsel arayüzleri kontrol edilen istisnalara izin vermediğinden (ve bunların yayılması gönderimin geri dönmesini önleyeceğinden) bunun kabul edilebilir olduğu varsayılır Function. Çalışma zamanı istisnaları ( RuntimeExceptionveya için atanabilir Error) yayılır.

Çıkış fonksiyonu

Gönderimin çıktısı a java.util.function.Function<Object, Object>. ObjectBir applyyöntemle (girişte olduğu gibi) bir düz döndürmeyi düşündüm , ancak daha sonra izin verilmeyecek kadar elverişsiz görünen sonucu çağırmak için yansıma gerekli olurdu - özellikle, tüm yolu çağırmak artık tek bir yerde mümkün olmayacaktı ifadesi.

kullanım

Sunulması ile ilgili bir fonksiyon verdiği için Objectiçin Object, çıkış (ile doğrudan çağrılan edilebilir apply), ancak daha sonra bir ara dönüş değerleri uygun bir türü (örn dökülmesi gerekir java.util.function.Function<Object, Object>çağrılmakta önce). Bazı kullanım örnekleri için TIO'ya başvurun.

Java işlevlerinde (yani yöntemler) birinci sınıf nesneler olmadığını unutmayın. Bu nedenle, meydan okuma açıklamasının çıkış mermisinde kullanılan sözdizimi Java'da anlamsızdır. Sahip f(a1, a2, a3)olduğumuzdan f.apply(a1, a2, a3)ziyade, sahip f(a1)(a2)(a3)olduğumuzdan çok f.apply(a1).apply(a2).apply(a3).

Sınırlamalar

Bir ara sonuç uygulandığında (bir argüman eklendi), sonuç aslında orijinal sonucun mutasyona uğramış bir kopyasıdır. Örneğin, bu snippet'te:

Function<Object, Function<Integer, Function>> submission = ...;
Function c = submission.apply((IntBinaryOperator) (a, b) -> a + b).apply(2);
Function c2 = (Function) c.apply(2);
System.out.println(c2.apply(2));
System.out.println(c2.apply(3));

satır 4 yazdırılır 4, ancak satır 5 başarısız olur, çünkü o zamana kadar c2zaten argümanlar tutar 2ve 2(bunu da unutmayın c2 == c). Bu, körelme ruhunu ihlal eder, ancak meydan okumada belirtilen özel gereksinimi karşılar.

Ungolfed

Kurtulmamış bir kopya için TIO'ya bakın.



0

APL (Dyalog Klasik) , 58 57 bayt

r←(a f g)x
:If a[1]=≢a
rg 1a,x
:Else
r←(a,x)f g
:End

Çevrimiçi deneyin!

(Curried fonksiyonu ile sözdizimi çağrılması g, argümanlar x1aracılığıyla x3ve argümanlar sayısı n):

((n x1 f g) x2) x3

gerektirir ⎕IO←1

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.