Menjumlahkan? Itu keahlian saya!

18

pengantar

Forte adalah bahasa esoterik yang sangat aneh berdasarkan konsep memodifikasi nilai-nilai angka. Dalam Forte angka bukan konstanta tetapi variabel, Anda bisa menggunakan LETinstruksi untuk memberikan nilai baru kepada mereka.

Misalnya, setelah mengeksekusi LET 2=4-1dari sekarang 2mengasumsikan nilai 3, yang berarti bahwa setiap kali nilai 2muncul dalam ekspresi itu malah "diganti" oleh 3. Ekspresi (1+1)*2sekarang akan dievaluasi menjadi 9.

Instruksi ini di Forte digunakan baik untuk menyimpan informasi dan untuk kontrol aliran (garis diberi nomor dan dengan mengubah nilai nomor mereka Anda dapat menentukan urutan pelaksanaannya). Dalam tantangan ini kita tidak akan berurusan dengan aspek kedua ini.

Tantangan

Anda diharuskan untuk menulis juru bahasa untuk subset LETekspresi Forte yang disederhanakan .

Anda akan menerima sebagai masukan serangkaian garis mengikuti tata bahasa ini:

<line>::= <number>=<expression>

<expression>::= <number>|<expression>+<number>

Catatan: tata bahasa ini tidak sahih Forte karena tidak memiliki nomor baris, LET, dan tanda kurung (yang selalu wajib)

Artinya, Anda hanya perlu berurusan dengan penjumlahan komputasi dan menetapkan nilai ke angka. Tanda kurung tidak akan ada dalam input, dan setiap ekspresi perlu dievaluasi dari kiri ke kanan: berhati-hatilah bahwa sebagian hasil dipengaruhi oleh redefinisi!

Angka akan selalu berupa bilangan bulat non-negatif, hingga batas jenis bilangan bulat asli bahasa Anda (atau 2 ^ 32, mana yang lebih tinggi).

Untuk setiap baris Anda harus menampilkan hasil dari ekspresi dan menetapkan hasil ini ke nilai (mungkin ditugaskan kembali) dari angka pertama, yang akan mempengaruhi bagaimana baris berikut akan ditafsirkan.

Ini adalah , kode terpendek (dalam byte) menang!

Aturan lainnya

  • Format input fleksibel, misalnya Anda dapat mengambil string tunggal dengan baris baru, daftar string, daftar daftar angka ... Hal yang sama berlaku untuk output, selama jelas apa hasil dari setiap ekspresi di input.
  • Anda dapat mengirimkan fungsi, program lengkap, atau solusi untuk dijalankan dalam lingkungan REPL yang memanggilnya sekali untuk setiap baris.
  • Celah standar dilarang, khususnya Anda tidak bisa memanggil juru bahasa Forte eksternal dalam kode Anda.

Contohnya

Ini semua adalah bagian dari input yang sama. Setelah setiap baris, output yang diharapkan relatif terhadap baris tersebut ditampilkan, kadang-kadang dengan komentar yang menunjukkan penugasan kembali yang relevan (bukan bagian dari output yang diperlukan).

5=4
4
6=5
4        # 5 -> 4
7=1+2+5
7
7=5+2+1
4        # Order of operations matters! 5+2 -> 4+2 -> 6 -> 4
18=5+6+7
12
5=3
3        # Remember: 5 -> 4
10=6+4
3        # 6 -> 4 -> 3, 3+3 = 6 -> 3
Leo
sumber
Apakah 0nomor itu valid?
orlp
@ orlp 0valid ("Angka akan selalu bilangan bulat non-negatif")
Leo
Haruskah kita menerima operator aritmatika?
bacchusbeale
@ bacchusbeale Tidak, hanya penjumlahan.
Leo
Apakah ada angka maksimum tertentu, atau sebesar angka integer asli bahasa tersebut? Juga, itu akan menjadi output yang tidak valid untuk mengembalikan daftar angka, salah satunya adalah hasilnya, kan? (seperti mencetak kamus / peta dengan nomor yang menuju ke nomor mana)
zgrep

Jawaban:

4

Jelly , 28 byte

®y$ÐL
ṪÇ+Ç¥/Ṅ;®⁸Ǥ;©
⁸©ḷƓÇ€¤

Cobalah online!

Ini adalah salah satu dari beberapa program Jelly yang sepertinya terser untuk mengambil input dari input standar. Ini adalah program lengkap (menulis fungsi akan lebih pendek tetapi dilarang oleh aturan PPCG, karena itu tidak akan berjalan dengan benar untuk kedua kalinya). Format input terlihat seperti ini:

[[5,[4]],[6,[5]],[7,[1,2,5]],[7,[5,2,1]],[18,[5,6,7]],[5,[3]],[10,[6,4]]]

Penjelasan

Fungsi pembantu 1Ŀ (menerjemahkan bilangan bulat ke nilainya)

®y$ÐL
   ÐL   Repeatedly, until there are no further changes,
  $       apply the following unary function to {the input}:
 y          replace values using the mapping table
®             stored in the register.
        {Then return the eventual result.}

Agak nyaman, fungsi pembantu ini akan bekerja dengan benar baik pada nilai tunggal, atau daftar nilai, karena cara ydidefinisikan Jika lebih dari satu pemetaan diberikan untuk nilai tunggal, kami mengambil pemetaan pertama dari tabel. Tabel pemetaan disimpan dalam register (yang pada dasarnya hanya variabel; Jelly hanya memiliki satu variabel).

Fungsi pembantu 2Ŀ (mengevaluasi satu instruksi LET)

ṪÇ+Ç¥/Ṅ;®⁸Ǥ;©
Ṫ               On the last element of {the input},
 Ç              Run 1Ŀ,
     /          left fold it via
    ¥             the following binary function:
  +                 add {the two arguments}
   Ç                and run 1Ŀ on {the result},
      Ṅ         write {the result} (and a newline) to standard output,
       ;®       append the value of the register,
            ;   prepend
           ¤      the following value:
         ⁸          {the input, without its last element}
          Ç         with 1Ŀ run on it
             ©  and store that value in the register {and return it}.

Kami tidak benar-benar menginginkan nilai pengembalian di sini; kami hanya menjalankan ini untuk efek sampingnya (memperbarui register dan mengeluarkan nilai yang ditugaskan). Fungsi Jelly selalu mengembalikan nilai, jadi kami hanya membiarkan tabel pemetaan dikembalikan, karena itu tersest.

Program utama

⁸©ḷƓÇ€¤
 ©       Initialize the mapping table
⁸        with the empty string (which is also the empty list)
  ḷ      then evaluate and discard
      ¤  the following value:
   Ɠ       a line from standard input, parsed into a data structure
    Ç€     with each element transformed via 2Ŀ
         {and leave the empty string to be printed implicitly}

Biasanya, akan memberi kita argumen command-line pertama ketika dijalankan dalam konteks ini, tetapi tidak ada satu (kita mengambil input dari input standar), jadi itu berjalan dalam mode alternatif yang memberi kita string nol. Kebutuhan untuk menginisialisasi register (dari nilai default-nya 0, yang crash y) berarti bahwa kita tidak dapat menyebutkan input pengguna secara implisit, artinya lebih murah untuk mengambilnya dari input standar ( Ɠ) seperti mengambilnya dari argumen baris perintah ( ³atau ), dan dapat mengakses penggunaan alternatif berarti bahwa bentuk input yang tidak biasa (untuk Jelly) sebenarnya satu byte lebih pendek.

Mungkin ini bisa diperbaiki. Saya masih belum tahu mengapa baris kedua perlu diucapkan ⁸Ǥ;daripada hanya ;@Ç- keduanya harus setara, sejauh yang saya mengerti Jelly, mengingat kurangnya penggunaan µ/ ð/ ø- tetapi yang terakhir crash karena beberapa alasan. Demikian juga, ada berbagai cara lain untuk mengatur ulang program tanpa kehilangan byte, jadi ada kemungkinan saya telah melewatkan cara untuk membuat segalanya sedikit lebih pendek.

Kebetulan, mengubah baris terakhir untuk ;memberi Anda pandangan menarik ke dalam cara kerja internal program, karena kemudian akan menampilkan "sejarah register" yang secara implisit dihasilkan oleh nilai pengembalian dari 2Ḷ.


sumber
5

Perl 5 , 92 byte

90 byte kode + -plbendera.

sub f{($b=$h{$a=pop}//$a)!=$a?f($b):$a}s%(\d+)\+(\d+)%f($1)+f$2%e&&redo;/=/;$_=$h{f$`}=f$'

Cobalah online!

Saya menggunakan hashtable %huntuk menyimpan pemetaan antar angka.
Fungsi ( sub) fmengembalikan nomor yang peta inputnya (atau inputnya jika dipetakan ke nomor): $h{$a=pop}mengambil nomor ke arah mana input peta. Jika tidak ada, terima kasih kepada //$a, nilai ($b=$h{$a=pop}//$a)inputnya adalah ( $a). Kami memastikan bahwa nilai-nilai ini bukan input itu sendiri untuk tidak berulang ( !=$a). Kemudian, kami memanggil fatau mengembalikan input secara rekursif .
Program utama terdiri dari dua langkah:
- s%(\d+)\+(\d+)%f($1)+f$2%e&&redomengevaluasi penambahan pertama di sisi kanan, sementara masih ada tambahan: ia menggantikan x+ydengan hasil evaluasi f(x)+f(y).
- /=/;$_=$h{f$`}=f$'melakukan penugasan:/=/memungkinkan untuk mengakses sisi kiri dengan $`dan sisi kanan dengan $', kemudian $h{f$`}=f$'melakukan penugasan. Dan kami juga menugaskannya untuk $_yang dicetak secara implisit setelah setiap baris.

Dada
sumber
5

JavaScript (Node.js) , 81 byte

v=x=>(v[x]=v[x]||x,v[x]-x?v(v[x]):x)
f=x=>l=>v[v(x)]=l.reduce((p,x)=>v(v(x)+p),0)

Cobalah online!

Menerima input dengan memanggil f dengan nilai untuk ditugaskan, lalu memanggil hasilnya dengan array nilai untuk ditambahkan bersama. (Yaitu f(5)([4])) Ulangi untuk beberapa baris.

vdigunakan sebagai fungsi untuk menghitung nilai aktual suatu angka, dan juga sebagai objek untuk menyimpan nilai aktual. Pertama, v[x]=v[x]||xpastikan hal v[x]itu didefinisikan. v[x]-xmelakukan perbandingan untuk menentukan apakah ini angka yang sebenarnya atau tidak. Jika nomor tidak memetakan ke dirinya sendiri, v(v[x])secara berulang coba lagi, jika tidak kembali x.

f melakukan perhitungan dan penugasan, mencari satu byte, di mana panggilan kedua mengembalikan nilai yang dihitung.

OinkIguana
sumber
3

Haskell , 116 113 108 106 byte

(#)=until=<<((==)=<<)
e?((n,s):r)|m<-foldl1(\a b->e#(e#a+e#b))s=m:(\x->last$m:[e#x|x/=e#n])?r
e?r=[]
(id?)

Cobalah online! Setiap persamaan 4=3+1+5dinotasikan sebagai tuple (4,[3,1,5]). Fungsi anonim (id?)mengambil daftar tupel tersebut dan mengembalikan daftar semua hasil antara.

#adalah fungsi untuk menemukan titik fokus dari fungsi yang diberikan edan nilai awal x.

Fungsi ini ?mengambil fungsi evaluasi edan memecahkan setiap persamaan secara rekursif. foldl1(\a b->e#(e#a+e#b))smengevaluasi sisi kanan persamaan dan menyimpan hasilnya m, misalnya untuk 4=3+1+5menghitungnya eval(eval(eval 3 + eval 1) + eval 5), di mana masing eval- masing merupakan aplikasi titik perbaikan e. Kemudian fungsi eval dimodifikasi untuk mempertimbangkan penugasan baru n: (\x->last$m:[e#x|x/=e#n])yang sama dengan \x -> if x == eval n then m else eval x.

Fungsi evaluasi awal adalah idmemetakan setiap bilangan bulat ke dirinya sendiri.


Terima kasih kepada Ørjan Johansen untuk fungsi fixpoint yang lebih pendek, menghemat 2 byte!

Laikoni
sumber
Pekerjaan yang baik! Ngomong-ngomong Anda diharuskan untuk mengembalikan semua hasil antara, sehingga Anda dapat menghapuslast.
Leo
2
(#)e=until((==)=<<e)eatau (#)=until=<<((==)=<<)lebih pendek.
Ørjan Johansen
@ ØrjanJohansen Terima kasih banyak!
Laikoni
3

OK, 48 byte

a:[];s:{*(a@x;x)^0N}/;f:{a[s@x]:y:{s@x+y}/s'y;y}

Pemakaian: f[5;1 2 3] / 5=1+2+3

Cobalah online!


Jika Anda tidak keberatan memiliki batas atas untuk angka-angka yang dapat Anda gunakan, seperti hanya menggunakan angka 0melalui 998, maka yang berikut sudah cukup ( 41 byte ± beberapa tergantung pada maksimum):

a:!999;s:(a@)/;f:{a[s@x]:y:{s@x+y}/s'y;y}

Penjelasan:

; memisahkan tiga definisi.

aadalah kamus / peta angka. Dalam kasus pertama, ini adalah kamus kosong yang sebenarnya [], dalam kasus kedua adalah daftar angka-angka 0untuk 998.

sadalah fungsi yang menemukan nomor "dihasilkan" ketika diberi nomor. Di /akhir fungsi berarti bahwa ia akan menerapkan sendiri ke output sendiri sampai output berhenti berubah.

Bit terakhir f,, berarti bahwa:

f:{                      } /function called f, input number x, list y
                    s'y    /apply s to every number in the list
                   /       /fold through the list
            {s@x+y}        /    sum the two numbers, apply s
   a[s@x]:                 /set the s(x) to map to the final sum
          y:           ;y  /redefine y to be the final sum, then return it
zgrep
sumber
3

Python 3, 146 132 130 byte

14 byte disimpan berkat @Dada
2 byte disimpan berkat @ mbomb007

d={}
g=lambda x:d.get(x)and x!=d[x]and g(d[x])or x
def f(t):
 for n,(s,*r)in t:
  for b in r:s=g(g(s)+g(b))
  d[g(n)]=s;yield g(n)

Cobalah online!

Menerima input sebagai tupel persamaan [ x = y + z + wsebagai (x, (y, z, w))], output melalui generator.

Uriel
sumber
Bisakah Anda menunjukkan contoh doa sehingga dapat diuji?
Leo
1
@ Leo menambahkan TIO.
Uriel
1
gmungkin bisa ditulis g=lambda x:d.get(x)and d[x]!=x and g(d[x])or x. Dan saya pikir Anda bisa menggunakan 1 spasi untuk indentasi daripada 2. Itu seharusnya membuat Anda [132 byte] ( Coba online! ).
Dada
1
@Dada terima kasih! Sayang sekali mereka tidak memiliki indentasi setengah-ruang: P
Uriel
1
Tidak ada indentasi setengah spasi, tetapi trik lain yang rapi adalah menggunakan satu tab alih-alih dua spasi. Selama lekukan berbeda, Python senang (misalnya Anda bisa menggunakan spasi-tab dan ruang-tab sebagai lekukan pada level bersarang tambahan). Ini dapat menghemat dua byte :)
Leo