Buatkan aku kari

20

Memiliki fungsi f yang mengambil argumen x 1 , x 2 ,…, x n

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

- currying mendefinisikan ulang f sebagai fungsi mengambil argumen tunggal a 1 yang memetakan fungsi lain. Teknik ini berguna untuk aplikasi parsial, misalnya dengan powfungsi kari yang bisa kita tulis exp = pow(e).

Contoh

Dengan asumsi kita memiliki fungsi berikut f mengambil tiga argumen ( f: X 1 × X 2 × X 3 → Y ):

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

Menjelajahi fungsi ini membuat kita dengan f_curry: X 1 → (X 2 → (X 3 → Y)) , jika kita sekarang memanggil fungsi itu dua kali dengan f_curry(1)(2)kita akan mendapatkan fungsi ( h) setara dengan yang dikembalikan berikut:

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

Fungsi kari fdapat ditulis seperti ini (Python 3):

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

Cobalah online!

Tantangan

Tantangan Anda adalah menjelajah fungsi seperti dijelaskan di atas, berikut adalah aturannya:

  • Input akan berupa fungsi kotak hitam yang membutuhkan setidaknya 2 argumen
  • Fungsi input akan selalu memiliki sejumlah argumen (tidak seperti printfatau mirip, catatan: Anda harus mendukung fungsi dengan sejumlah argumen ≥2)
  • Jika bahasa Anda menggunakan fungsi curried secara default (mis. Haskell), Anda mungkin mengharapkan fungsi input didefinisikan lebih dari N -tuple, alih-alih "fungsi urutan lebih tinggi"
  • Anda dapat mengambil jumlah argumen sebagai input
  • Output akan menjadi setara input kari *
  • Anda dapat mengasumsikan bahwa fungsi output hanya akan:
    • dipanggil dengan kurang atau sama dengan jumlah argumen yang diambil oleh fungsi input
    • dipanggil dengan argumen dari tipe yang tepat

* Ini berarti input fdengan Nargumen dan output hyang untuk semua argumen valid a1,…,aNitu berlaku f(a1,a2,…,aN) == h(a1)(a2)…(aN).

ბიმო
sumber
Terkait .
ბიმო
jadi inputnya def f(a,b,c): return a + b * cdan outputnya def f_curry(a): def g_curry(b): def h(c): return a + b * c return h return g_curry?
DanielIndie
@DanielIndie: Jika Anda mengambil contoh input akan f(yang didefinisikan di suatu tempat) dan output harus setara dengan f_curry. Atau inputnya lambda a,b,c: a+b*cdan output fungsi yang setara f_curry.
ბიმო
Ini sulit dilakukan di sebagian besar bahasa yang diketik secara statis ... Saya kira Anda perlu mengetikkan fungsi untuk ini.
Paŭlo Ebermann
@ PaŭloEbermann: Benar, beberapa bahasa tidak akan dapat menyelesaikan tugas ini (perhatikan tag -pemrograman fungsional ). Namun beberapa bahasa yang diketik secara statis mungkin dapat menggunakan pointer fungsi yang akan menjadi I / O yang valid, itu terutama alasan saya memperbolehkan mengambil jumlah argumen sebagai input tambahan.
ბიმო

Jawaban:

11

JavaScript (ES6), 35 byte

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

Idris , 204 byte

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))

Cobalah online!

Kedengarannya seperti pekerjaan untuk tipe dependen! Ya, mungkin.


C adalah fungsi jenis kari. Diberikan vektor tipe a = [t 1 , t 2 ,… t n ] dan fungsi tipe T: HVect a → Type , ia mengembalikan tipe baru:

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

Di sini, HVect adalah tipe vektor yang heterogen dari Idris Prelude - tipe n -tupel yang elemen-elemennya dari n tipe berbeda.

c adalah fungsi yang mengambil a dan T sebagai argumen implisit, dan kemudian mengubah fungsi tipe yang tidak terburu - buru ((b: HVect a) → T b) menjadi curriedf salah satu jenis C T .

( C hanya menggambarkan apa yang ingin kita lakukan; c benar-benar melakukannya. Tapi kita tidak bisa lolos dengan tidak mendefinisikan C , karena Idris menuntut agar setiap definisi tingkat atas memiliki jenis tanda tangan.)


TIO link memberikan contoh penggunaan. Jika kita mendefinisikan suatu fungsi pada 3-tupel (Nat, Nat, String) sebagai berikut:

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

kemudian uncurried [3, 4, "th"]menghasilkan hasil yang sama dengan c uncurried 3 4 "th". Idris menyimpulkan argumen a=[Nat, Nat, String]dan T=const Stringbagi kami, saya percaya.

Saya mendasarkan kode ini pada inti ini oleh timjb.

Lynn
sumber
Menurut pendapat saya, tuple di Haskell dan Idris seharusnya secara HVectdefault — HVectpada dasarnya adalah tuple yang bisa Anda buka.
Buah Esolanging
5

R , 96 byte

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))

Cobalah online!


Versi sebelumnya (97 byte)

-1 byte terima kasih kepada @JayCE

menggali semua
sumber
Saya tidak melihat bagaimana mempersingkatnya secara mendasar . Anda dapat bermain golf tiga byte dengan menyingkirkan kawat gigi dan ruang di akhir baris pertama. Dan dua lagi karena konvensi di sini tidak termasuk nama fungsi dalam jumlah byte. TIO
ngm
@ ngm Nama fungsi harus dimasukkan saat rekursif.
Ørjan Johansen
@ ngm: Saya meletakkan pernyataan if di dalam sub-fungsi, menyimpan sepersepuluh byte :)
digEmAll
3

Python 2 , 60 byte

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

Cobalah online!

Footer adalah tester yang menggunakan STDIN dengan cara berikut per baris:

  1. Fungsinya sendiri
  2. Jumlah argumen fungsi, ≥2
  3. Daftar argumen ([a,b,...] )

Perhatikan bahwa, sementara daftar argumen diberikan sebagai input dalam tester, pada kenyataannya, ekuivalen kari akan ditambahkan ke daftar dan daftar dikurangi oleh pemanggilan fungsi.

Versi 55 byte yang serupa telah disediakan oleh ovs :

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

Cobalah online!

Erik the Outgolfer
sumber
2

Kembang kol , 84 byte

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

Cobalah online!

Khusus ASCII
sumber
1
Mmm, kari kembang kol. Lezat. ^ _ ^
DLosc
@Dosc, tidak ada jawaban yang cukup untuk tantangan ini dalam bahasa dengan nama-nama yang berhubungan dengan makanan: P (walaupun saya rasa kebanyakan dari mereka tidak benar-benar memiliki fungsi)
ASCII-hanya
2

Perl 6 , 42 40 byte

my&c={.count>1??{c(.assuming($^a))}!!$_}

Cobalah online!

-2 byte berkat b2gills Brad Gilbert .

nwellnhof
sumber
Anda tidak perlu menggunakan trailing *, hanya perlu jika ada sesuatu setelahnya .assuming(*,1).
Brad Gilbert b2gills
1

Attache , 5 byte

Curry

Cobalah online!

Sederhana dibangun, sebagian besar tidak menarik. Tapi, ini versi dari awal:

Attache, 35 byte

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

Penjelasan:

{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
Conor O'Brien
sumber
1

Java 8, 46 + 318 = 364 byte

Ini adalah lambda kari (hah) yang mengambil fungsi dan argumen menghitung dan mengembalikan fungsi kari.

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;}}}

Cobalah secara Online

Jenis pengiriman

Fungsi input

Input fungsi adalah objek dengan metode tunggal (tidak termasuk metode yang diwarisi) yang mewakili fungsi. Perhatikan bahwa antarmuka fungsional standar tidak dapat digunakan sebagai tipe input karena fungsi (misalnya) 3 parameter harus didukung. Perhatikan juga bahwa ekspresi lambda yang dilemparkan ke java.util.function.Functiontipe seperti standar dapat dilewatkan (metode tunggal adalah apply).

Pengecualian yang diperiksa dapat dideklarasikan pada fungsi input, tetapi mereka mungkin tidak dilempar (yaitu mereka tidak akan disebarkan ke pemanggil fungsi output). Ini dianggap dapat diterima karena antarmuka fungsional Java tidak mengizinkan pengecualian diperiksa (dan menyebarkannya akan mencegah pengajuan mengembalikan a Function). Pengecualian runtime (dapat diberikan kepada RuntimeExceptionatau Error) diperbanyak.

Fungsi output

Output dari pengajuan adalah a java.util.function.Function<Object, Object>. Saya mempertimbangkan untuk mengembalikan dataran Objectdengan applymetode (seperti pada input), tetapi kemudian refleksi diperlukan untuk meminta hasilnya, yang tampaknya cukup tidak nyaman untuk disangkal - khususnya, memanggil semua jalan ke bawah tidak akan mungkin lagi dalam satu ekspresi.

Pemakaian

Karena pengiriman mengembalikan fungsi dari Objectke Object, output dapat dipanggil secara langsung (dengan apply), tetapi nilai-nilai pengembalian menengah berikutnya harus dilemparkan ke jenis yang sesuai (misalnya java.util.function.Function<Object, Object>) sebelum dipanggil. Konsultasikan dengan TIO untuk beberapa contoh penggunaan.

Perhatikan bahwa fungsi Java (yaitu metode) bukan objek kelas satu. Jadi sintaks yang digunakan dalam bullet output dari deskripsi tantangan tidak ada artinya di Jawa. Daripada yang f(a1, a2, a3)kita miliki f.apply(a1, a2, a3), dan bukan yang f(a1)(a2)(a3)kita miliki f.apply(a1).apply(a2).apply(a3).

Keterbatasan

Ketika hasil antara diterapkan (argumen ditambahkan), hasilnya sebenarnya adalah salinan hasil asli yang dimutasi. Misalnya, dalam cuplikan ini:

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));

baris 4 akan dicetak 4, tetapi baris 5 akan gagal, karena pada saat itu c2sudah memegang argumen 2dan 2(perhatikan juga itu c2 == c). Ini melanggar semangat kari, tetapi memenuhi persyaratan khusus yang dinyatakan dalam tantangan.

Tidak disatukan

Lihat TIO untuk salinan yang tidak diseragamkan.

Jakob
sumber
1

Julia 0,6 , 48 byte

c=(f,n,a=[])->n>1?x->c(f,n-1,[a;x]):x->f(a...,x)

Cobalah online!

Port of @ EricTheOutgolfer menjawab Python.

sundar - Pasang kembali Monica
sumber
0

APL (Dyalog Classic) , 58 57 byte

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

Cobalah online!

Sintaks pemanggilan (dengan fungsi curried g, argumen x1melalui x3, dan jumlah argumen n):

((n x1 f g) x2) x3

Membutuhkan ⎕IO←1

Zacharý
sumber