Julia: Operator infiks khusus

Dibuat pada 17 Jun 2016  ·  65Komentar  ·  Sumber: JuliaLang/julia

Ada diskusi di https://groups.google.com/forum/#!topic/julia -dev/FmvQ3Fj0hHs tentang membuat sintaks untuk operator infix khusus.

...

Diedit untuk menambahkan catatan: @johnmyleswhite telah menunjukkan bahwa utas komentar di bawah ini adalah undangan untuk bikeshedding. Harap menahan diri dari komentar baru kecuali Anda memiliki sesuatu yang benar-benar baru untuk ditambahkan. Ada beberapa proposal di bawah ini, ditandai dengan emoticon "hore" (kerucut meledak). Anda dapat menggunakan ikon-ikon tersebut untuk melewatkan diskusi dan hanya membaca proposal, atau untuk menemukan proposal yang berbeda sehingga Anda dapat memilih "jempol ke atas" atau "jempol ke bawah".

Up/downvotes pada bug ini secara keseluruhan adalah tentang apakah menurut Anda Julia harus memiliki idiom infix khusus. Suara naik/turun untuk ide spesifik di bawah ini harus diberikan pada komentar pertama @ Glen-O. (Bug memiliki 3 downvotes dan 1 upvote sebelum diklarifikasi.)

...

Proposal awal (hanya minat historis):

Proposal yang tampaknya telah menang adalah:

    a |>op<| b #evaluates (in the short term) and parses (in the long term) to `op(a,b)`

Untuk memiliki pekerjaan ini, hanya ada perubahan kecil yang diperlukan:

  • Letakkan prioritas <| di atas |> , alih-alih sama.
  • Buat grup <| dari kiri ke kanan.
  • Buat fungsi <|(a,b...)=(i...)->a(i...,b...) . (seperti yang ditunjukkan di utas diskusi, ini akan memiliki kegunaan mandiri, serta penggunaannya dalam idiom di atas)

Pilihan:

  • buat fungsi baru >|(a...,b)=(i...)->b(a...,i...) dan |<(a,b...)=a(b...) dengan prioritas dan pengelompokan yang sesuai.

    • Pipa pertama berarti evaluasi, dan pipa terakhir mempertahankannya sebagai fungsi, sedangkan > dan < menunjukkan yang mana yang merupakan fungsi.

  • buat fungsi baru >>|(a...,b)=(i...)->b(i...,a...) dan <<|(a,b...)=(i...)->a(b...,i...) dengan prioritas dan pengelompokan yang sesuai.
  • buat sinonim » , , dan(/atau) pipe untuk |> ; « , , dan(/atau) rcurry untuk <| ; dan(/atau) lcurry untuk <<| ; dengan sinonim karakter tunggal yang berfungsi sebagai operator infiks.
  • buat makro @infix di basis yang melakukan perbaikan parser pertama di bawah ini.

Jangka panjang:

  • ajarkan parser untuk mengubah a |>op<| b menjadi op(a,b) , sehingga tidak ada overhead tambahan yang terlibat saat menjalankan kode, dan agar operator benar-benar dapat didefinisikan dalam posisi infix. (Ini mirip dengan bagaimana parser saat ini memperlakukan biner a:b dan ternary a:b:c secara berbeda. Untuk kemampuan penyesuaian maksimum, parser harus melakukan ini untuk sinonim yang cocok, tetapi tidak untuk sinonim yang tidak cocok, sehingga mis. a |> b « c akan tetap diperlakukan sebagai dua operator biner.)
  • ajari pengurai untuk memahami koma dan/atau spasi sehingga elips dalam definisi di atas berfungsi seperti yang diharapkan tanpa tanda kurung tambahan.

(terkait dengan https://github.com/JuliaLang/julia/issues/6946)

parser speculative

Komentar yang paling membantu

Stefan tidak lebih senior dariku.

Semua 65 komentar

Menggemakan utas julia-dev, saya pikir akan berguna untuk mengutip komentar utama Stefan pada proposal ini:

Hanya untuk menetapkan harapan di sini, saya tidak berpikir akan ada banyak cara "inovasi sintaksis" sebelum Julia 1.0. (Satu-satunya pengecualian yang dapat saya pikirkan adalah sintaksis pemanggilan vektor f.(v) yang baru.) Meskipun memiliki beberapa cara untuk membuat fungsi arbitrer berperilaku seperti operator infix mungkin bagus, itu bukan masalah mendesak dalam bahasa.

Sebagai seseorang yang berpartisipasi dalam proporsi yang baik dari sejarah pengembangan Julia, saya pikir akan lebih baik untuk memfokuskan energi pada perubahan semantik daripada yang sintaksis. Ada banyak masalah semantik yang sangat penting yang harus diselesaikan sebelum Julia mencapai 1.0.

Perhatikan khususnya bahwa menerapkan fitur ini bukan hanya perbedaan satu kali yang hanya perlu dipikirkan oleh penulis: setiap orang harus memikirkan bagaimana pekerjaan mereka berinteraksi dengan fitur ini ke depannya, sehingga perubahan tersebut sebenarnya meningkatkan jangka panjang beban kerja setiap orang yang bekerja pada parser.

Saya pikir komentar johnmyleswhite sangat tepat mengenai perubahan parser "jangka panjang" yang disarankan. Tetapi grup "perubahan kecil" dan "opsional", sejauh yang saya lihat, cukup mandiri dan berdampak rendah.

Yaitu: perubahan parser yang diperlukan untuk mengaktifkan versi minimal proposal ini hanya melibatkan prioritas dan pengelompokan untuk operator biner normal, jenis perubahan yang kurang lebih rutin dalam kasus lain. Pengembang parser yang mengerjakan sesuatu yang tidak terkait tidak perlu lagi melacak ini daripada yang mereka butuhkan untuk melacak arti dari semua operator yang sudah ada.

Secara pribadi saya menemukan sintaks ini cukup jelek dan sulit untuk diketik. Tapi saya setuju akan lebih baik untuk memiliki sintaks infix yang lebih umum.

Saya pikir cara yang tepat untuk memikirkan ini adalah sebagai masalah sintaks saja: yang Anda inginkan adalah menggunakan op dengan sintaks infix, jadi mendefinisikan fungsi dan operator lain untuk mendapatkan itu adalah bundaran. Dengan kata lain itu semua harus dilakukan di parser.

Saya benar-benar akan mempertimbangkan untuk mengklaim kembali | untuk ini, dan menggunakan a |op| b . Bisa dibilang sintaks infix umum lebih penting daripada bitwise atau. (Kami telah berbicara tentang merebut kembali operator bitwise sebelumnya; mereka tampak seperti pemborosan sintaksis.)

a f b tersedia di luar rangkaian array dan sintaks panggilan makro.

a f b mungkin berhasil, tetapi tampaknya cukup rapuh. Bayangkan mencoba menjelaskan kepada seseorang mengapa a^2 f b^2 f c^2 legal tetapi a f b c dan a+2 f b+2 f c+2 tidak. (Saya tahu, yang terakhir mengasumsikan bahwa prioritas adalah waktu sebelum, tetapi tidak peduli apa prioritasnya, hal umum ini menjadi perhatian).

Mengenai a |op| b : awalnya saya menyukai proposal serupa, a %op% b , seperti yang Anda lihat di utas grup google. Tetapi hal yang menyenangkan tentang |> dan <| yang diusulkan adalah bahwa mereka masing-masing berguna secara individual sebagai operator biner, dan mereka secara alami bergabung untuk bekerja seperti yang diinginkan (diberikan prioritas dan pengelompokan yang tepat, yaitu. ) Ini berarti Anda dapat menerapkan ini dalam jangka pendek menggunakan mekanisme parser yang ada, dan dengan demikian menghindari membuat sakit kepala bagi pengembang parser di masa mendatang, seperti yang saya katakan dalam tanggapan saya terhadap johnmyleswhite di atas.

Jadi sementara saya suka a |op| b dan tentu saja tidak akan menentangnya, saya pikir kita harus mencari cara untuk memiliki dua operator berbeda untuk menyederhanakan perubahan parser yang diperlukan. Jika kita menginginkan kemampuan mengetik maksimum dan tidak menentang memiliki | berarti "pipa" daripada "bitwise atau", lalu bagaimana dengan a |op\\ b atau a |op& b ?

"sakit kepala untuk pengembang parser" adalah kekhawatiran serendah mungkin.

"sakit kepala untuk pengembang parser" adalah kekhawatiran serendah mungkin.

Sebagai pengembang parser, saya sangat setuju dengan ini.

|> dan <| keduanya adalah operator infix yang sangat baik, tetapi tidak ada manfaat untuk mengimplementasikan sintaks operator umum menggunakan dua operator lain. Dan masih banyak lagi yang perlu dikatakan tentang betapa verbose dan tidak menarik sintaksis itu.

tidak ada manfaat untuk mengimplementasikan sintaks operator umum menggunakan dua operator lain.

Untuk lebih jelasnya, visi jangka panjang di sini adalah bahwa akan ada biner f <| y , biner x |> f , dan ternary x |> f <| z , di mana yang pertama hanyalah sebuah fungsi tetapi yang kedua dua diimplementasikan sebagai transformasi di parser.

Gagasan bahwa ini dapat diimplementasikan menggunakan dua fungsi biasa |> dan <| hanyalah jembatan sementara untuk visi itu.

Dan masih banyak lagi yang perlu dikatakan tentang betapa verbose dan tidak menarik sintaksis itu.

Itu poin yang adil. Bagaimana kalau mengganti |> dan <| dengan | dan & ? Mereka masuk akal baik sebagai pasangan dan individu, meskipun mereka mungkin sedikit menggelegar bagi pemain hoki sedikit.

Mencuri | dan & untuk ini tidak akan menjadi alokasi ASCII yang baik, dan saya menduga banyak yang lebih suka pembatas menjadi simetris.

Jika orang menginginkan operator ternary x |> f <| y karena alasan lain, tidak apa-apa, tetapi saya pikir itu harus dipertimbangkan secara terpisah. Saya tidak yakin parser harus mengubah |> menjadi <| yang dibalik. Operator serupa lainnya seperti < tidak bekerja seperti itu. Tapi itu juga masalah yang terpisah.

Mencuri keduanya | dan & untuk ini tidak akan menjadi alokasi ASCII yang baik, dan saya menduga banyak yang lebih suka pembatasnya simetris.

OKE.

Saya mengerti bahwa > dan < sulit untuk diketik. Dalam hal simetri dan tipabilitas pada keyboard standar, saya kira yang paling mudah mungkin seperti &% dan %& , tapi itu sangat jelek, paralel R atau tidak. /| dan |/ mungkin layak dipertimbangkan juga.

...

Saya tidak yakin pengurai harus mengubah |> menjadi <| . yang dibalik

Saya pikir Anda telah salah paham. a |> b harus diurai menjadi b(a) . (Versi tanpa penguraian khusus adalah ((x,y)->y(x))(a,b) , yang mengevaluasi hal yang sama, tetapi dengan lebih banyak overhead.)

a |> b harus diurai menjadi b(a)

Ah, oke, mengerti.

Saya pikir kita bisa berbagi tentang karakter mana yang akan digunakan selama bertahun-tahun. Saya akan mempercayai @StefanKarpinski (sebagai orang paling senior dalam percakapan ini sejauh ini) untuk membuat keputusan, dan saya akan setuju dengan itu. Bahkan jika itu adalah sesuatu yang saya bantah (seperti a f b .)

Berikut beberapa opsi untuk melihat apa yang menarik:
a |>op<| b (tidak mengubah |> saat ini)
a |{ op }| b (keadaan shift terdekat dan sama pada banyak keyboard umum, tidak terlalu jelek. Agak aneh sebagai standalone.)
a \| op |\ b atau a /| op |/ b atau kombinasinya
a $% op %$ b (relatif dapat diketik, terinspirasi R. Tapi agak jelek.)
a |% op %| b
a |- op -| b
a |: op :| b
a | op \\ b
a | op ||| b
a op b

Stefan tidak lebih senior dariku.

Sepertinya Anda baru saja menominasikan diri Anda sendiri, lalu, untuk kekuatan BDFL dalam masalah ini! ;)

a @op@ b ?

Saya kira suara saya adalah menggunakan semua 4 dari \| , |\ , /| , dan |/ . Turun untuk evaluasi, naik untuk kari; bar menuju fungsi. Jadi:
a \| f (atau f |/ a ) -> f(a)
a /| f (atau f |\\ a ) -> (b...)->f(a,b...)
f |\ b (atau b //| f ) -> (a...)->f(a...,b)
dan dengan demikian:
a \| f |\ b (atau a /| f |/ b ) -> f(a,b)
a \| f |\ b |\ c (atau a /| b /| f |/ c ) -> f(a,b,c)

Masing-masing dari 4 operator utama, kecuali mungkin |/ , berguna dengan sendirinya. Redundansi tentu saja tidak Pythonik, tetapi saya pikir kerapian logisnya adalah Julian. Dan sebagai praktisnya, Anda dapat menggunakan versi mana pun dari idiom infiks yang menurut Anda lebih mudah untuk diketik; keduanya sama-sama dapat dibaca, karena begitu Anda mempelajari satu, Anda secara alami memahami keduanya.

Jelas, akan sama masuk akalnya jika Anda menukar semua garis miring, sehingga panah atas untuk evaluasi dan panah bawah untuk kari.

Saya masih menunggu kabar dari On High (dan saya mohon maaf atas kecanggungan newbie saya dalam menebak apa maksudnya). Tetapi jika ada yang lebih tinggi dari bikeshed ini membuat keputusan, untuk ini atau versi lain dengan setidaknya dua simbol baru, saya akan dengan senang hati menulis tambalan jangka pendek (menggunakan fungsi) dan/atau yang tepat (menggunakan transformasi).

Kami mencoba untuk menghindari BDFL sejauh mungkin :)

Saya hanya berpikir saya akan mencatat beberapa hal cepat.

Pertama, manfaat lain ("penggunaan mandiri") dari notasi yang diusulkan adalah bahwa <| dapat digunakan dalam konteks lain, dengan cara yang meningkatkan keterbacaan. Misalnya, jika Anda memiliki larik string, A , dan ingin menambahkan semuanya di sebelah kiri ke 10, sekarang, Anda harus menulis map(i->lpad(i,10),A) . Ini relatif sulit untuk dibaca. Dengan notasi ini, menjadi map(lpad<|10,A) , yang menurut saya Anda akan setuju jauh lebih bersih.

Kedua, ide di balik ini adalah untuk menjaga agar notasi tetap konsisten. Sudah ada operator |> , yang ada untuk mengubah "fix" pemanggilan fungsi dari prefix ke postfix. Ini hanya memperluas notasi.

Ketiga, kemungkinan penggunaan direct infix sebagai a f b memiliki masalah yang lebih besar. a + b dan a * b pada akhirnya harus memiliki prioritas yang sama, karena + dan * adalah nama fungsi, dan sistem tidak dapat melakukannya memiliki prioritas variabel. Itu, atau harus memperlakukan operator infix yang ada secara berbeda, yang dapat menyebabkan kebingungan.

Misalnya, jika Anda memiliki larik string, A , dan ingin menambahkan semuanya di sebelah kiri ke 10, sekarang, Anda harus menulis map(i->lpad(i,10),A) . Ini relatif sulit untuk dibaca. Dengan notasi ini, menjadi map(lpad<|10,A) , yang menurut saya Anda akan setuju jauh lebih bersih.

Saya tegas tidak setuju. Sintaks yang diusulkan adalah – maafkan saya – salad ASCII, mendekati beberapa pelanggaran terburuk Perl dan APL, tanpa preseden dalam bahasa lain untuk memberikan petunjuk kepada pembaca biasa tentang apa yang terjadi. Sintaks saat ini, sementara beberapa karakter lebih panjang (lima?), Cukup jelas bagi siapa saja yang mengetahui bahwa i->expr adalah sintaks lambda – yang ada dalam kumpulan bahasa yang besar dan terus bertambah.

a + b dan a * b pada akhirnya harus memiliki prioritas yang sama, karena + dan * adalah nama fungsi, dan tidak mungkin sistem memiliki prioritas variabel. Itu, atau harus memperlakukan operator infix yang ada secara berbeda, yang dapat menyebabkan kebingungan.

Saya tidak berpikir ini adalah masalah nyata; kita hanya bisa mengatakan apa yang didahulukan dari infiks a f b , dan menjaga semua tingkat prioritas yang ada juga. Ini berfungsi karena prioritas ditentukan oleh nama fungsi; fungsi apa pun yang disebut "+" akan didahulukan "+".

Ya, kami sudah melakukan ini untuk sintaks 1+2 in 1+2 , dan itu tidak menjadi masalah.

Saya tidak berpikir ini adalah masalah nyata; kita hanya bisa mengatakan apa yang didahulukan dari infiks afb, dan menjaga semua tingkat prioritas yang ada juga. Ini berfungsi karena prioritas ditentukan oleh nama fungsi; fungsi apa pun yang disebut "+" akan didahulukan "+".

Saya tidak bermaksud sulit untuk menulis parser agar berfungsi. Maksud saya itu mengarah ke masalah konsistensi, maka saya mengatakan "atau itu harus memperlakukan operator infix yang ada secara berbeda, yang dapat menyebabkan kebingungan". Antara lain, pertimbangkan bahwa ¦ dan tidak terlihat terlalu berbeda dalam konsep, namun yang satu adalah operator infiks yang telah ditentukan, sementara yang lain tidak.

Saya tegas tidak setuju. Sintaks yang diusulkan adalah – maafkan saya – salad ASCII, mendekati beberapa pelanggaran terburuk Perl dan APL, tanpa preseden dalam bahasa lain untuk memberikan petunjuk kepada pembaca biasa tentang apa yang terjadi. Sintaks saat ini, sementara beberapa karakter lebih panjang (lima?), Cukup jelas bagi siapa saja yang tahu bahwa i->expr adalah sintaks lambda – yang ada dalam kumpulan bahasa yang besar dan terus bertambah.

Mungkin saya harus lebih jelas tentang apa yang saya katakan. Saya mengatakan bahwa mampu menggambarkan operasi sebagai "lpad oleh 10" jauh lebih jelas daripada i->lpad(i,10) membuatnya. Dan menurut saya, lpad<|10 adalah yang terdekat yang bisa Anda dapatkan, dalam bentuk non-konteks.

Mungkin akan membantu jika saya menjelaskan dari mana saya berasal. Saya seorang ahli matematika dan fisikawan matematika, pertama dan terutama, dan "sintaks lambda", meskipun masuk akal dari sudut pandang pemrograman, bukan yang paling jelas bagi mereka yang kurang berpengalaman dalam pemrograman. Julia, seperti yang saya pahami, terutama ditujukan untuk menjadi bahasa komputasi ilmiah, oleh karena itu sangat mirip dengan MATLAB.

Saya harus bertanya - bagaimana lpad<|10 lebih "salad ASCII" daripada, katakanlah, x|>sin|>exp ? Namun notasi |> telah ditambahkan. Bandingkan dengan, katakanlah, skrip bash, di mana | digunakan untuk meneruskan argumen di sebelah kiri ke perintah di sebelah kanan - jika Anda tahu itu disebut "pipa", itu membuat _little_ lebih masuk akal, tetapi jika Anda 'tidak terampil dalam pemrograman, itu tidak akan masuk akal. Dalam hal itu, |> sebenarnya lebih masuk akal, karena terlihat samar-samar seperti panah. Dan kemudian <| adalah ekstensi alami untuk notasi.

Bandingkan dengan beberapa saran lain, seperti %func% , yang _mempunyai preseden dalam bahasa lain, tetapi tidak jelas bagi orang yang tidak memiliki pengetahuan luas tentang pemrograman dalam bahasa tersebut.

Pikiran Anda, saya melihat kembali sedikit pada salah satu diskusi yang lebih tua, dan saya melihat bahwa telah ada notasi yang digunakan dalam bahasa lain yang akan cukup bagus, secara teori. Haskell tampaknya menggunakan a |> b c d untuk mewakili b(a,c,d) . Jika spasi setelah nama fungsi memungkinkan Anda untuk menentukan "parameter" dengan cara ini, itu akan berfungsi dengan baik - map(lpad 10,A) . Satu-satunya masalah yang muncul dengan operator unary - map(+ 10,A) akan menghasilkan kesalahan, misalnya, karena akan ditafsirkan pada "+10" alih-alih i->+(i,10) .

Pada a f b : masalah prioritas mungkin tidak seburuk yang disarankan Glen-O, tetapi kecuali fungsi infix yang ditentukan pengguna memiliki prioritas paling rendah, mereka memang ada. Katakanlah, demi argumen, kami memberi mereka pra-waktu. Dalam hal itu,
a^2 f b^2 => f(a^2,b^2)
a+2 f b+2 => a+f(2,b)+2
a^2 f^2 b^2 => (f^2)(a^2,b^2)
a f+2 b => kesalahan sintaks?

Ini semua adalah konsekuensi alami dari bagaimana Anda akan menulis parser, jadi tidak terlalu sakit kepala dalam pengertian itu. Tapi itu tidak terlalu intuitif untuk pengguna biasa dari idiom.

Tentang kegunaan idiom kari
Saya setuju dengan Glen-O bahwa (i)->lpad(i,10) lebih buruk daripada lpad<|10 (atau, jika kita memilihnya, lpad |\ 10 , atau apa pun). i adalah beban kognitif yang sama sekali asing dan sumber kesalahan potensial; sebenarnya, saya bersumpah bahwa ketika saya mengetik itu sekarang, saya tidak sengaja mengetik (i)->lpad(x,10) pada awalnya. Jadi, melakukan operasi kari infiks menurut saya adalah ide yang bagus.
Namun, jika itu tujuannya, maka apa pun idiom infiks yang kita tetapkan, kita dapat membuat operasi kari kita sendiri. Jika a f b , maka sesuatu seperti lpad rcurry 10 akan baik-baik saja. Intinya adalah keterbacaan, bukan penekanan tombol. Jadi saya pikir ini hanya argumen yang lemah untuk <| .

Pada a |> b c d
Saya sangat menyukai proposal ini. Saya pikir kita bisa membuatnya sehingga |> menerima spasi di kedua sisi, jadi a b |> f c d => f(a,b,c,d) .

(Catatan: Jika kedua saran saya a b |> f c d dan Glen-O dari map(lpad 10,A) , ini membuat kasus sudut: (a b) |> f c d => f((x)->a(x,b),c,d) . Tapi saya pikir itu bisa ditoleransi.)

Ini masih memiliki masalah serupa dalam hal prioritas operator sebagai a f b . Tapi entah bagaimana saya pikir mereka lebih dapat ditoleransi jika Anda setidaknya dapat membicarakannya dalam hal prioritas operator |> , daripada menjadi prioritas operator ternary dengan .

Coba lpad.(["foo", "bar"], 10) pada 0,5. |> yang ada tidak sepenuhnya disukai oleh semua orang.

@tkelman : Saya melihat masalahnya, tapi apa maksud Anda? Anda pikir kami harus memperbaiki |> yang ada sebelum kami menambahkan kegunaan tambahan untuk itu? Jika demikian, bagaimana?

Saya pribadi berpikir kita harus menyingkirkan |> yang ada.

Coba lpad.(["foo", "bar"], 10) pada 0,5. |> yang ada tidak sepenuhnya disukai oleh semua orang.

Saya pikir Anda telah melewatkan intinya. Ya, notasi func.() bagus, dan melewati masalah dalam beberapa situasi. Tapi saya menggunakan fungsi map sebagai demonstrasi sederhana. Fungsi apa pun yang menggunakan fungsi sebagai argumen akan diuntungkan oleh pengaturan ini. Sebagai contoh, murni untuk menunjukkan maksud saya, Anda mungkin ingin mengurutkan beberapa angka berdasarkan kelipatan persekutuan terkecilnya dengan beberapa nomor referensi. Mana yang terlihat lebih rapi dan lebih mudah dibaca: sort(A,by=i->lcm(i,10)) atau sort(A,by=lcm 10) ?

Saya ingin mencatat sekali lagi bahwa cara apa pun untuk mendefinisikan operator infix akan memungkinkan pembuatan operator yang melakukan apa yang diinginkan Glen-O <| , sehingga paling buruk dia akan dapat menulis sesuatu seperti sort(A,by=lcm |> currywith 10) . Inti dari halaman ini adalah untuk membahas bagaimana membuat a ... f ... b => f(a,b) . Saya mengerti bahwa apakah |> yang ada atau <| yang diusulkan adalah operator yang bermanfaat memiliki beberapa hubungan ke titik itu, tetapi mari kita coba untuk tidak terlalu teralihkan.

Secara pribadi, saya pikir proposal a |> b c adalah yang terbaik sejauh ini. Ini mengikuti konvensi yang ada dari Haskell; itu secara logis terkait dengan operator |> yang ada; itu cukup mudah dibaca dan cukup mudah diketik. Fakta bahwa saya merasa bahwa itu secara alami meluas ke kegunaan lain adalah sekunder. Jika Anda tidak setuju, mohon setidaknya sebutkan perasaan Anda pada idiom inti, bukan hanya kegunaan sekunder yang diusulkan.

Maksud saya itu mengarah ke masalah konsistensi, maka saya mengatakan "atau itu harus memperlakukan operator infix yang ada secara berbeda, yang dapat menyebabkan kebingungan".

Saya setuju sulit untuk memutuskan prioritas untuk a f b . Misalnya in jelas diuntungkan dari prioritas perbandingan, tetapi kemungkinan besar banyak fungsi yang digunakan sebagai infiks tidak menginginkan prioritas perbandingan. Namun saya tidak melihat masalah konsistensi. Operator yang berbeda memiliki prioritas yang berbeda. Menambahkan a f b tidak memaksa tangan kita untuk memberikan + dan * prioritas yang sama.

Perhatikan bahwa |> sudah memiliki prioritas yang berdekatan dengan perbandingan. Untuk prioritas lainnya, terus terang, saya pikir tanda kurung baik-baik saja.

Jika Anda tidak setuju dengan saya, dan jika kami menggunakan a |> f b , maka mungkin ada operator serupa |+> , |*> , dan |^> , yang bekerja sama dengan |> , tetapi memiliki prioritas dari operator pusatnya. Saya pikir itu berlebihan tapi itu kemungkinan.

Kemungkinan lain untuk memecahkan masalah prioritas adalah dengan menggunakan sintaks untuk operator infiks khusus yang menyertakan tanda kurung, misalnya (a f b) .

Diskusi terkait: https://github.com/JuliaLang/julia/issues/554 , https://github.com/JuliaLang/julia/issues/5571 , https://github.com/JuliaLang/julia/pull/14476 , https://github.com/JuliaLang/julia/issues/11608 , dan https://github.com/JuliaLang/julia/issues/15612.

Saya harus bertanya - bagaimana lpad<|10 lagi "salad ASCII" daripada, katakanlah, x|>sin|>exp? Namun notasi |> ditambahkan.

Saya membayangkan bahwa @tkelman berdebat

kita harus menyingkirkan |> yang ada.

sebagian karena _keduanya_ lpad<|10 dan x|>sin|>exp menjelajah ke wilayah ASCII-salad :).

Saya pikir @toivoh 's (a f b) , dengan parens wajib, adalah proposal terbaik sejauh ini.

Terkait dengan https://github.com/JuliaLang/julia/issues/11608 (dan dengan demikian juga https://github.com/JuliaLang/julia/issues/4882 dan https://github.com/JuliaLang/julia/pull /14653): Jika (a f b) => f(a,b) , maka masuk akal jika (a <strong i="8">@m</strong> b) => (<strong i="10">@m</strong> a b) . Ini akan memungkinkan penggantian logika makro kasus khusus yang ada untuk y ~ a*x+b dengan normal (dan dengan demikian jauh lebih transparan) (y @~ a*x+b) .

Juga, "diperlukan parens" bisa menjadi idiom yang lebih disukai untuk definisi infiks yang ringkas. Alih-alih mengatakan (menggunakan contoh bodoh) a + b = string(a) * string(b) , Anda akan didorong (oleh alat lint, atau oleh peringatan kompiler) untuk mengatakan (a + b) = string(a) * string(b) . Saya menyadari bahwa ini sebenarnya bukan konsekuensi langsung dari memilih opsi "diperlukan parens" untuk infiks, tetapi ini adalah idiom yang nyaman yang memungkinkan kita untuk memperingatkan orang-orang yang menggunakan infiks di LHS secara keliru tetapi memberhentikan orang-orang yang melakukannya tujuan.

Perasaan saya saat ini adalah jika Anda menerapkan fungsi infiks (bukan awalan),
maka itu adalah operator, dan harus terlihat dan bertindak seperti operator.

Dan kami memiliki dukungan untuk operator infix yang ditentukan menggunakan unicode.
sejak https://github.com/JuliaLang/julia/issues/552

Saya kira mungkin bagus untuk memiliki itu sehingga Anda dapat menambahkan kata kunci seperti pada saran asli.
Jadi kita bisa memiliki, misalnya, 1 ⊕₂ 1 == 0
Mampu memiliki nama arbitrer untuk infiks Anda tampaknya agak berlebihan.

harus terlihat dan bertindak seperti operator.

Saya setuju bahwa harus ada konvensi penamaan yang kuat untuk operator infix. Misalnya: satu karakter unicode, atau diakhiri dengan preposisi. Tetapi itu harus berupa konvensi yang berkembang secara organik, bukan persyaratan yang diberlakukan oleh kompiler. Tentu saja, saya tidak berpikir bahwa #552 adalah akhir dari cerita; jika ada lusinan operator yang dikodekan secara keras, harus ada cara untuk menambahkan lebih banyak secara terprogram, jika hanya untuk membuat prototipe fitur baru.

...

Bagi saya, proposal (a f b) (dan (a <strong i="10">@m</strong> b) ) lebih unggul dari proposal lainnya dalam bug ini. Saya hampir tergoda untuk membuat tambalan.

(a f b) => f(a,b)
(a f b c d) => f(a,b,c,d)
(a f) => kesalahan sintaks
(a+2 f+2 b+2) => (f+2)(a+2,b+2)
(t1=a t2=f t3=b) => (t1=f)((t2=a),(t3=b)) (spasi memiliki prioritas serendah mungkin, seperti pada makro)

...

Apakah tidak pantas bagi saya untuk mengirimkan tambalan?

Saya tidak mengerti dua kasus terakhir:

(a+2 f+2 b+2)=>(f+2)(a+2,b+2)
(t1=a t2=f t3=b)=>(t1=f)((t2=a),(t3=b))

Saya menemukan sintaks (a f b c d) sangat aneh. Karena 1 + 2 + 3 dapat ditulis sebagai +(1,2,3) maka bukankah f(a,b,c) dapat ditulis sebagai (a f b f c) ?

Secara keseluruhan saya pribadi tidak yakin Julia harus mendukung operator infix khusus di luar apa yang saat ini diizinkan.

Saya dapat melihat dua masalah dengan (a f b c d) .

Pertama, akan sulit untuk membaca ketika Anda memiliki ekspresi yang lebih rumit - salah satu alasan mengapa tanda kurung bisa membuat frustasi adalah sering kali sulit untuk membedakan, secara sekilas, tanda kurung mana yang berpasangan dengan tanda kurung lainnya. Itu sebabnya operator infix dan postfixing ( |> ) diinginkan sejak awal. Postfixing khususnya disukai karena memungkinkan pembacaan kiri-ke-kanan yang bagus dan rapi tanpa harus berurusan dengan tanda kurung setiap saat.

Kedua, tidak ada cara untuk melakukan hal-hal seperti membuatnya menjadi elemen. Pemahaman saya adalah bahwa f.(a,b) akan menjadi notasi dalam 0,5 untuk membuat f beroperasi secara elemen pada argumennya dengan penyiaran. Tidak akan ada cara rapi untuk melakukan hal yang sama dengan notasi infiks, jika (a f b) . Paling-paling, itu harus (a .f b) , yang menurut saya kehilangan keindahan simetri yang .( berikan dengan .+ dan .* .

Bandingkan, misalnya, kasus ingin menggunakan contoh dari Haskell. shashi di #6946 membuat poin yang setara di sini. Di Haskell, Anda akan menulis circle 10 |> move 0 0 |> animate "scale" "ease" . Menggunakan notasi ini, ini menjadi ((circle(10) move 0 0) animate "scale" "ease") , yang tidak lebih jelas dari animate(move(circle(10),0,0),"scale","ease") . Dan jika Anda ingin menyalin lingkaran Anda ke beberapa tempat, menggunakan notasi |> , Anda mungkin memiliki circle 10 .|> copy [1 15 50] [3 14 25] . Dalam pandangan saya, itu adalah cara paling rapi untuk mengimplementasikan ide - dan kemudian, tanda kurung melakukan peran normalnya dalam menangani urutan masalah operasi.

Dan seperti yang telah saya tunjukkan, a|>f b c memiliki manfaat juga memiliki ekstensi alami yang memungkinkan notasi yang sama untuk digunakan lebih banyak - f b c akan diuraikan sebagai "fungsi f dengan parameter b dan c set), dan dengan demikian akan setara dengan i->f(i,b,c) Ini memungkinkannya berfungsi tidak hanya untuk infiks, tetapi untuk situasi lain di mana Anda mungkin ingin meneruskan sebuah fungsi (terutama fungsi bawaan) dengan parameter (mencatat bahwa standarnya adalah memiliki objek fungsi terlebih dahulu).

|> juga memperjelas yang mana fungsinya. Jika Anda memiliki, katakanlah, (tissue wash fire dirty metal) , sekilas akan sulit untuk mengenali wash sebagai fungsi. Di sisi lain, tissue|>wash fire dirty metal memiliki indikator besar yang mengatakan " wash adalah fungsi".

Beberapa keberatan terbaru bagi saya terdengar seperti mengatakan "tetapi Anda dapat menyalahgunakan fitur ini!" Tanggapan saya adalah: tentu saja Anda bisa. Anda sudah bisa menulis kode yang sama sekali tidak dapat dibaca menggunakan makro jika Anda mau. Tugas parser adalah mengaktifkan penggunaan yang sah; untuk menghentikan penyalahgunaan, kami memiliki konvensi/idiom dan dalam beberapa kasus menghapus. Secara khusus:

Saya tidak mengerti dua kasus terakhir:

Ini tidak dimaksudkan untuk menjadi contoh untuk diikuti; mereka hanya menunjukkan konsekuensi alami dari aturan prioritas. Saya pikir kedua dari dua contoh terakhir akan memenuhi syarat sebagai menyalahgunakan sintaks, meskipun (a^2 ಠ_ಠ b^2) => ಠ_ಠ(a^2,b^2) sudah cukup jelas.

tidakkah f(a,b,c) harus ditulis sebagai (afbfc)

Proposal saya tentang (a f b c d) , sejujurnya, adalah renungan. Saya pikir itu masuk akal, dan saya bisa memberikan contoh di mana itu berguna, tetapi saya tidak ingin menutup proposal ini tentang masalah ini jika itu kontroversial.

[Misalnya:

  • f adalah "metode objek" dari objek a, mungkin rumit, menggunakan b, c, dan d, mungkin lebih sederhana.
  • f adalah metode "siaran alami" seperti push! ]

Meskipun (a f b f c) akan masuk akal jika f seperti + , saya pikir sebagian besar operator sebenarnya tidak seperti + , jadi itu tidak boleh menjadi model kita.

akan sulit dibaca ketika Anda memiliki ekspresi yang lebih rumit

Sekali lagi, jawaban saya adalah, "jadi jangan disalahgunakan".

Katakanlah kita ingin beberapa cara untuk menulis ekspresi rumit seperti a / (b + f(c,d^e)) dengan f infix. Dalam proposal @toivoh , itu akan menjadi a / (b + (c f d^e)) . Dalam penggunaan seperti Haskell, itu akan menjadi a / (b + (c |> f d^e)) atau pada "terbaik", jika prioritas |> diubah untuk memperbaiki satu contoh khusus ini, a / (b + c |> f d^e) . Saya pikir @toivoh 's semudah itu di sini.

(tissue wash fire dirty metal)

Saya pikir solusi untuk ini adalah konvensi penamaan yang kuat untuk operator infix. Misalnya, jika ada konvensi bahwa operator infiks harus satu karakter unicode, atau diakhiri dengan preposisi atau garis bawah, maka di atas akan menjadi sesuatu seperti (tissue wash_ fire dirty metal) yang sejelas ekspresi yang pernah diharapkan untuk menjadi .

...

dari segi elemen

Ini adalah kekhawatiran yang valid. (a .f b) adalah ide yang buruk, karena dapat dibaca sebagai ((a.f) b) . Saran pertama saya adalah (a ..f b) tetapi itu tidak membuat saya sangat senang.

circle 10 |> move 0 0 |> animate "scale" "ease"

Saya telah menggunakan jquery, jadi saya pasti melihat keuntungan dari fungsi chaining seperti itu. Tapi saya pikir itu bukan masalah yang sama dengan operator infix. Dengan menggunakan proposal (a f b) , Anda dapat menulis di atas sebagai:

circle 10 |> (move <| 0 0) |> (animate <| "scale" "ease")

... yang tidak sesingkat versi Haskell, tetapi masih cukup mudah dibaca.

Mungkin dapat dibatasi hanya pada tiga hal di dalam () :
(a f (b,c))
.(a f (b,c)) menggunakan operator .(

Akhirnya, tanggapan terhadap poin umum:

Secara keseluruhan saya pribadi tidak yakin Julia harus mendukung operator infix khusus di luar apa yang saat ini diizinkan.

Jelas kita semua berhak atas pendapat kita. (Saya tidak jelas apakah acungan jempol mengacu pada bagian komentar itu, tetapi jika demikian, itu menjadi tiga kali lipat.)

Tapi argumen balik saya adalah:

  • Julia sudah memiliki lusinan operator infix, banyak di antaranya sangat niche. Tidak dapat dihindari bahwa lebih banyak akan diusulkan. Ketika seseorang mengatakan "bagaimana Anda bisa memiliki tetapi tidak § ?", Saya lebih suka menjawab "lakukan sendiri" dan bukan "tunggu sampai versi berikutnya diadopsi secara luas".
  • Sesuatu seperti (a § b) sangat mudah dibaca, dan sintaksnya cukup ringan untuk dipelajari dari satu atau dua contoh.
  • Saya bukan orang pertama yang mengangkat masalah ini, dan saya tidak akan menjadi yang terakhir. Saya mengerti bahwa perancang bahasa harus sangat skeptis terhadap fitur yang merayap (mis), karena begitu Anda menambahkan fitur yang jelek, pada dasarnya tidak mungkin untuk memperbaikinya nanti. Tapi seperti yang saya katakan di atas, saya pikir (a f b) cukup bersih sehingga Anda tidak akan menyesalinya.

Saya benar-benar tidak yakin dengan kejelasan (a f b)

Berikut adalah kemungkinan kasus penggunaan:
select((((:emp_id, :last_name) from employee_tbl) where (:city, == ,'indianapolis')) orderby :emp_id));

Ini tentu saja layak menggunakan fungsi infix.
Fungsi select adalah fungsi identitas, atau mengirimkan kueri yang dibuat ke database.

Apakah ini kode yang jelas?
Aku hanya tidak tahu.

.(a f b)

Ya, itu masuk akal. Tapi itu tidak terlalu bisa dibaca.

Apakah (a @. f b) lebih mudah dibaca? Karena makro @. untuk mengaktifkannya akan menjadi satu baris sederhana.

[[[Kalau dipikir-pikir, jika kita mengizinkan makro infix tanpa memerlukan parens, @Glen-O dapat menggunakannya untuk melakukan apa yang dia inginkan: circle(10) @> move 0 0 @> animate "scale" "ease" => @> (@> circle(10) move 0 0) animate "scale" "ease" =macro> animate(move(circle(10),0,0),"scale","ease") . Saya pikir solusi itu lebih buruk dari (a f b) , tetapi setidaknya itu akan menyelesaikan bug keseluruhan ini di mata saya.]]]

...

select((((:emp_id, :last_name) from employee_tbl) where (:city, = ,'indianapolis')) orderby :emp_id);

Saya pasti lebih suka menggunakan makro untuk "di mana" sehingga ekspresi kondisional tidak perlu dikutip secara aneh. Jadi:

select((((:emp_id, :last_name) from employee_tbl) <strong i="22">@where</strong> city == 'indianapolis') orderby :emp_id);

Parens agak mengganggu, tetapi di sisi lain saya tidak melihat cara yang masuk akal bagi parser untuk menangani ekspresi semacam ini tanpa mereka.

select((((:emp_id, :last_name) from employee_tbl) <strong i="6">@where</strong> city == 'indianapolis') orderby :emp_id);

Parens agak mengganggu, tetapi di sisi lain saya tidak melihat cara yang masuk akal bagi parser untuk menangani ekspresi semacam ini tanpa mereka.

Setelah dipikir-pikir, prioritas dalam ekspresi itu tepat dari kanan ke kiri. Jadi, menggunakan makro infix, bisa juga:

select((:emp_id, :last_name) <strong i="11">@from</strong> employee_tbl <strong i="12">@where</strong> city == 'NYC' <strong i="13">@orderby</strong> :emp_id)

atau bahkan:

<strong i="17">@select</strong> (:emp_id, :last_name) <strong i="18">@from</strong> employee_tbl <strong i="19">@where</strong> city == 'NYC' <strong i="20">@orderby</strong> :emp_id

Jadi sementara saya masih suka (a f b) , saya mulai melihat bahwa makro infiks juga merupakan jawaban yang bagus.

Berikut proposal lengkapnya melalui contoh, berikut kelebihan dan kekurangannya:

kegunaan utama:

  • a <strong i="28">@m</strong> b => <strong i="30">@m</strong> a b
  • a <strong i="33">@m</strong> b c => <strong i="35">@m</strong> a b c
  • a <strong i="38">@m</strong> b <strong i="39">@m2</strong> c => <strong i="41">@m2</strong> (<strong i="42">@m</strong> a b) c
  • <strong i="45">@defineinfix</strong> f; a <strong i="46">@f</strong> b => macro f(a,b...) :(f($a,$b...)) end; <strong i="48">@f</strong> a b => f(a,b)

Kasus sudut: (tidak dimaksudkan sebagai kode yang baik, hanya untuk menunjukkan cara kerja parser)

  • t1=a <strong i="54">@m</strong> t2=b t3=c => <strong i="56">@m</strong> t1=a t2=b t3=c (walaupun ini bukan gaya pemrograman yang baik)
  • t1 + a <strong i="59">@m</strong> t2 + b => <strong i="61">@m</strong> t1+a t2+b (walaupun ini bukan gaya pemrograman yang baik)
  • a b <strong i="64">@m</strong> c => kesalahan sintaks (??)
  • a <strong i="67">@m</strong> b [c,d] => tolong jangan, tapi <strong i="70">@m</strong> a b[c,d] (ETA: Tidak, dengan tambalan ini muncul sebagai <strong i="72">@m</strong> a b ([c,d]) yang mungkin lebih baik.)
  • a <strong i="75">@m</strong> b ([c,d]) => <strong i="77">@m</strong> a b ([c,d])
  • [a <strong i="80">@m</strong> b] => gaya buruk, harap gunakan tanda kurung untuk memperjelas, tetapi [a (<strong i="83">@m</strong> b)] (??)
  • a @> f b => @> a f b => f(a,b)
  • <strong i="90">@outermacro</strong> a b <strong i="91">@m</strong> c d => <strong i="93">@outermacro</strong> a (<strong i="94">@m</strong> b c d)

Keuntungan:

  • definisikan makro infiks, dapatkan fungsi infiks secara gratis (dengan satu kali overhead evaluasi makro. Itu tidak serendah overhead parser, tapi jauh lebih baik daripada memiliki fungsi tambahan memanggil setiap evaluasi)
  • dapat mengarah ke DSL yang kuat, seperti yang terlihat pada contoh seperti SQL di atas
  • Menghilangkan kebutuhan akan operator |> yang terpisah, karena itu adalah makro satu baris. Demikian pula untuk <| dan proposal @Glen-O lainnya.
  • eksplisit, jadi sangat rendah risiko digunakan secara tidak sengaja, tidak seperti (a f b)
  • Seperti yang ditunjukkan, makro @defineinfix dapat memungkinkan penggunaan singkatan untuk fungsi, bukan makro.

(Kecil) Kekurangan:

  • prioritas dan pengelompokan tampaknya berfungsi dengan baik dalam banyak kasus dengan RtoL, tetapi akan ada pengecualian yang memerlukan parens.
  • Saya pikir a @> f b atau bahkan a <strong i="112">@f</strong> b tidak begitu mudah dibaca seperti (a f b) (meskipun mereka juga tidak terlalu mengerikan.)

Mengingat betapa aktifnya utas ini, saya akan mengingatkan orang-orang tentang keprihatinan awal saya dengan topik ini: masalah tentang sintaksis sering kali menghasilkan sejumlah besar aktivitas, tetapi jumlah aktivitas itu umumnya tidak sebanding dengan nilai jangka panjangnya. perubahan yang sedang diperdebatkan. Sebagian besar, itu karena utas tentang sintaksis akhirnya menjadi dekat dengan argumen murni tentang selera.

jumlah aktivitas itu umumnya di luar proporsi

Maafkan saya. Saya mungkin yang paling bersalah karena terlibat bolak-balik.

Di sisi lain, saya pikir utas ini telah membuat kemajuan yang "dapat digunakan". Salah satu saran terbaru (a f b) atau [ a @> f b , dengan a <strong i="10">@f</strong> b didefinisikan sebagai jalan pintas] jelas lebih unggul dalam pandangan saya daripada saran sebelumnya seperti a %f% b atau a |> f <| b .

Namun, saya pikir komentar bolak-balik lebih lanjut mungkin tidak akan membuat kemajuan lebih lanjut, dan saya akan mendorong orang untuk menggunakan jempol atau jempol ke bawah mulai sekarang kecuali mereka memiliki sesuatu yang benar-benar baru untuk disarankan (itu bukan hanya perubahan ortografis pada proposal yang sudah ada). Saya telah menambahkan emotikon "hore" (kerucut yang meledak) ke "proposal yang dapat dipilih". Jika Anda yakin bahwa kami seharusnya tidak memiliki sintaks khusus untuk fungsi arbitrer di posisi infiks, maka turunkan bug secara keseluruhan.

...

ETA: Saya pikir diskusi ini sekarang cukup matang untuk mendapatkan tag decision .

Untuk referensi, (dan saya mengharapkan orang lain untuk menunjukkannya).
Jika Anda ingin menyematkan sintaks seperti SQL, alat yang tepat untuk pekerjaan itu adalah Literal String Tidak Standar, saya pikir.
Seperti semua makro, mereka memiliki akses ke semua variabel dalam cakupan saat dipanggil,
dan mereka memungkinkan Anda untuk menentukan DSL Anda sendiri, dengan pilihan prioritas Anda sendiri, dan mereka berjalan pada waktu kompilasi.

select((((:emp_id, :last_name) from employee_tbl) where (:city, == ,"indianapolis")) orderby :emp_id));

Lebih baik ditulis

sql"SELECT emp_id, last_name FROM employee_tbl WHERE city == 'indianapolis' ORDER BY emp_id"

Literal string yang tidak standar adalah sintaks yang sangat kuat.
Saya tidak dapat menemukan contoh bagus dari mereka yang digunakan untuk menyematkan DSL.
Tapi mereka bisa melakukannya.

Dan dalam hal ini saya pikir hasilnya jauh lebih bersih daripada operasi infiks apa pun yang dapat didefinisikan.
Meskipun memiliki overhead karena harus menulis microparser/tokenizer Anda sendiri.


Saya benar-benar tidak melihat perlunya tag keputusan.
Ini tidak memiliki implementasi sebagai PR, atau prototipe yang dapat digunakan.
yang memungkinkan orang mengujinya.
Kontras dengan https://github.com/JuliaLang/julia/issues/5571#issuecomment -205754539 dengan 8 prototipe yang dapat digunakan

Perasaan saya terhadap ini naik turun setiap kali saya membaca utasnya. Saya tidak berpikir saya akan benar-benar tahu sampai saya mencobanya. Dan sekarang saya bahkan tidak tahu untuk apa saya akan menggunakannya. (Tidak seperti beberapa definisi untuk |> dan <| yang saya gunakan di F#)

Sintaks seperti SQL, alat yang tepat untuk pekerjaan itu adalah Literal String Tidak Standar

Apakah SQL paling baik dilakukan dengan NSL atau tidak, saya pikir ada tingkat DSL yang cukup kompleks sehingga makro sebaris akan sangat membantu, tetapi tidak terlalu rumit sehingga layak untuk menulis microparser/tokenizer Anda sendiri.

sekarang saya bahkan tidak tahu untuk apa saya akan menggunakannya. (Tidak seperti beberapa definisi untuk |> dan <| yang telah saya gunakan di F#)

Proposal makro sebaris akan memungkinkan orang untuk, antara lain, menggulung |> -seperti atau <| -seperti makro mereka sendiri, sehingga Anda dapat menggunakannya untuk apa pun yang telah Anda lakukan di F#.

(Saya tidak ingin masuk ke argumen bikeshedding bolak-balik, tetapi saya tetap merespons karena di bawah ini, dan saya pikir proposal makro sebaris membunuh banyak burung dengan satu batu yang relatif mulus.)

Saya benar-benar tidak melihat perlunya tag keputusan.

Saya bertanya sebelumnya apakah pantas bagi saya untuk membuat parser patch, dan tidak ada yang menjawab. Satu-satunya kata yang sejauh ini adalah:

Saya tidak berpikir akan ada banyak cara "inovasi sintaksis" sebelum Julia 1.0.

Yang tampaknya menentang membuat tambalan sekarang, karena mungkin hanya duduk-duduk dan sedikit membusuk. Namun, sekarang Anda mengatakan bahwa tidak ada gunanya membuat keputusan tentang ini (termasuk keputusan untuk tidak memutuskan sekarang?) kecuali jika kita memiliki "implementasi sebagai PR [atau] prototipe yang dapat digunakan".

Apa artinya? (Apa itu PR?) Apakah makro yang menggunakan karakter '@' alih-alih token @ berfungsi, sehingga <strong i="22">@testinline</strong> a '@'f b => @f(a, b) ? Atau haruskah saya mengirimkan patch ke julia-parser.scm? (Saya sebenarnya sudah mulai melihat untuk menulis tambalan seperti itu, dan kelihatannya seharusnya sederhana, tetapi Skema saya sangat berkarat.) Apakah saya perlu membuat kasus uji?

Saat ini, ada 13 peserta dalam bug ini. Ada total 5 orang yang telah memilih satu atau lebih proposal dan/atau menurunkan bug itu sendiri, dan hanya satu dari mereka (saya) yang melakukannya setelah proposal makro sebaris ada di atas meja. Itu tidak membuat saya yakin bahwa sudah waktunya untuk membuat prototipe. Ketika jumlah orang yang telah memberikan suara sejak proposal serius terakhir lebih seperti setengah jumlah peserta, saya berharap semacam konsensus kasar akan menjadi jelas, dan kemudian akan tiba saatnya untuk membuat prototipe dan menguji dan memutuskan (atau, sebagai kasusnya mungkin, menyerah pada gagasan itu).

Dengan "implementasi sebagai PR [atau] prototipe yang dapat digunakan".
Maksud saya sesuatu yang bisa dimainkan.
Jadi bisa dilihat bagaimana rasanya dalam praktek.

PR adalah permintaan tarik, jadi tambalan adalah istilah yang Anda gunakan.

Jika Anda membuat PR, itu bisa diunduh dan diuji.
Lebih sederhana jika Anda menerapkannya dengan makro
atau literal string Nonstardard,
itu bisa diuji tanpa harus membangun julia.

Sepertinya itu bukan panggilan saya, tapi saya ragu saya akan berani membuat pendapat saya sendiri tanpa sesuatu yang bisa saya mainkan.

Juga +1 untuk tidak bolak-balik sepeda shedding.

...atau mungkin paket Infix.jl dengan makro dan literal string yang tidak standar.

Kami pasti telah mencapai titik "kode kerja atau GTFO" dalam percakapan ini.

OK, inilah kode yang berfungsi: https://github.com/jamesonquinn/JuliaParser.jl

ETA: Haruskah saya mereferensikan komit tertentu, atau apakah tautan di atas ke master terbaru OK?

...

(Itu tidak memiliki makro kenyamanan yang saya harapkan Anda inginkan, seperti padanan untuk |> , <| , ~ , dan @defineinfix dari contoh saya di atas. Juga tidak menghapus _deprecate_ logika kasus khusus yang sekarang tidak berguna untuk operator ~ atau |> . Ini hanya perubahan parser untuk membuatnya berfungsi. Saya sudah menguji fungsionalitas dasar tetapi tidak semua kasus sudut.

...

Saya pikir peretasan jelek saat ini dengan ~ menunjukkan bahwa ada kasus penggunaan yang jelas untuk hal semacam ini. Menggunakan tambalan ini, Anda akan mengatakan @~ ketika Anda membutuhkan perilaku makro; jauh lebih bersih, tanpa kasus khusus. Atau adakah yang benar-benar percaya bahwa ~ benar-benar unik dan tidak akan ada yang mau melakukannya lagi?

Perhatikan bahwa patch (ini belum menjadi PR karena menargetkan parser bootstrap asli, tetapi untuk saat ini skema yang harus didahulukan dalam hal PR) umumnya lebih berguna daripada nama masalah di sini. Nama masalah adalah "operator infix khusus"; tambalan memberikan makro infiks, dengan operator infiks hanya datang sebagai efek samping dari itu.

Tambalan sebagaimana adanya bukanlah perubahan yang melanggar, tetapi saya berharap jika ini menjadi rencana, langkah selanjutnya adalah menghentikan ~ dan |> yang ada saat ini, yang pada akhirnya akan mengarah ke melanggar perubahan.

...

Beberapa tes sederhana ditambahkan.

11608 ditutup dengan konsensus yang cukup jelas bahwa banyak dari kita tidak menginginkan makro infiks dan satu kasus penguraian ~ saat ini adalah kesalahan (dibuat sejak awal untuk kompatibilitas R dan tidak ada alasan bagus lainnya). Kami bermaksud untuk menghentikan dan akhirnya menyingkirkannya, hanya saja belum melakukannya (bersama dengan pekerjaan memodifikasi API untuk antarmuka formula dalam paket JuliaStats).

Makro sekarang secara teknis generik, tetapi argumen inputnya selalu Expr , Symbol , atau literal. Jadi mereka tidak benar-benar dapat diperluas ke tipe baru yang didefinisikan dalam paket seperti fungsi (infix atau lainnya). Kemungkinan kasus penggunaan untuk makro infiks lebih baik dilayani oleh DSL makro beranotasi awalan atau literal string.

(Maaf saya memposting sebelum waktunya; diperbaiki sekarang.)

Di #11608, saya melihat beberapa argumen negatif:

===

Apa yang akan diubah menjadi?
...
y = 0.0 @in@ x == 1.0 ? 1 @in@ 2 : 3 @in@ 4

Ini dibahas di utas:

Kasus seperti itulah mengapa saya selalu menggunakan tanda kurung...

dan

preseden yang sama ... berlaku tanpa makro: 0.0 in 1 == 1.0 ? 2 in 2 : 3 in 4

===

lebih banyak fungsionalitas untuk Julia yang harus diterapkan, dipelihara, diuji, dipelajari, digunakan, dll.

yang (sebagian) dijawab (dan diperbantukan) di sini oleh:

"sakit kepala untuk pengembang parser" adalah kekhawatiran serendah mungkin.

===

apakah tidak ada cara bagi 2 paket untuk secara bersamaan memiliki definisi untuk operator makro yang sama yang dapat digunakan bersama dengan jelas dalam satu basis kode pengguna?

Ini adalah hal yang menarik. Jelas, jika makro hanya memanggil suatu fungsi, maka kita memiliki semua kekuatan pengiriman fungsi tersebut. Tetapi jika itu adalah makro yang sebenarnya, seperti ~ , maka itu lebih rumit. Ya, Anda dapat membayangkan solusi peretasan, seperti mencoba menyebutnya sebagai fungsi, dan menangkap kesalahan apa pun untuk menggunakannya sebagai makro... tetapi keburukan semacam itu tidak boleh didorong.

Namun, ini adalah masalah yang sama untuk makro mana pun. Jika dua paket sama-sama mengekspor makro, Anda tidak dapat memiliki keduanya dengan "menggunakan".

Apakah ini lebih merupakan masalah dengan makro infix? Yah, itu tergantung untuk apa orang akhirnya menggunakannya:

  • Hanya cara untuk memiliki fungsi infix yang ditentukan pengguna. Dalam hal ini, mereka tidak lebih buruk dari fungsi lainnya; pengiriman berfungsi dengan baik.
  • Sebagai cara untuk menggunakan gaya pemrograman lain, gunakan operator seperti |> dan <| yang dibahas @Glen-O di atas. Dalam hal ini, saya pikir akan dengan cepat mengembangkan konvensi umum tentang apa arti makro, dengan sedikit kemungkinan tabrakan.
  • Sebagai cara untuk membuat DSL tujuan khusus, seperti contoh SQL di atas. Saya pikir ini akan digunakan dalam konteks tertentu dan kemungkinan tabrakan tidak terlalu buruk.
  • Untuk hal-hal seperti R's ~ . Pada awalnya, ini terlihat paling bermasalah; di R, ~ digunakan untuk beberapa hal yang berbeda. Namun, saya pikir bahkan di sana, itu dapat dikelola, dengan sesuatu seperti:

macro ~(a,b) :(~(:$a, quote($b))) end

Kemudian, fungsi ~ dapat dikirim berdasarkan jenis LHS, tetapi RHS akan selalu menjadi Ekspr. Hal semacam ini akan memungkinkan penggunaan utama yang dimilikinya di R (regresi dan grafik) untuk hidup berdampingan, yaitu, untuk mengirim dengan benar meskipun berasal dari paket yang berbeda.

(catatan: di atas telah diedit. Awalnya, saya pikir ekspresi R seperti a ~ b + c menggunakan pengikatan b dan c melalui evaluasi lazy R. Tapi ternyata tidak' t; b dan c adalah nama kolom dalam bingkai data yang diteruskan secara eksplisit, bukan nama variabel dalam lingkup lokal yang diteruskan secara implisit.)

===

Satu-satunya jalan ke depan di sini adalah dengan mengembangkan implementasi yang sebenarnya.

Yang telah saya lakukan.

===

Makro sekarang secara teknis generik, tetapi argumen inputnya selalu Expr, Symbol, atau literal. Jadi mereka tidak benar-benar dapat diperluas ke tipe baru yang didefinisikan dalam paket seperti fungsi (infix atau lainnya).

Hal ini berkaitan dengan poin di atas. Sejauh makro infiks memanggil fungsi tertentu, fungsi itu masih dapat diperluas melalui pengiriman dengan cara biasa. Sejauh tidak memanggil fungsi tertentu, ia melakukan sesuatu struktural/sintaksis (seperti apa yang |> lakukan sekarang) yang tidak boleh diperpanjang atau didefinisikan ulang. Perhatikan bahwa meskipun memanggil fungsi, fakta bahwa itu adalah makro masih bisa berguna; misalnya, ia dapat mengutip beberapa argumennya, atau memprosesnya menjadi panggilan balik, atau bahkan berinteraksi secara bersamaan dengan nama dan pengikatan variabel, dengan cara yang tidak dapat dilakukan oleh panggilan fungsi langsung.

===

Kemungkinan kasus penggunaan untuk makro infiks lebih baik dilayani oleh DSL makro beranotasi awalan atau literal string.

Seperti yang ditunjukkan di utas yang dirujuk:

[Infix] lebih mudah diurai (untuk penutur bahasa Inggris dan kebanyakan bahasa barat), karena bahasa kami bekerja seperti itu. (Hal yang sama umumnya berlaku untuk operator.)

Misalnya, mana yang lebih mudah dibaca (dan bisa ditulisi):

select((:emp_id, :last_name) <strong i="8">@from</strong> employee_tbl <strong i="9">@where</strong> city == 'NYC' <strong i="10">@orderby</strong> :emp_id)

atau

send(orderby((<strong i="14">@where</strong> selectfrom((:emp_id, :last_name), employee_tbl) city == 'NYC'), :emp_id))

?

===

Akhirnya:

11608 ditutup dengan konsensus yang cukup jelas

Tampak cukup merata bagi saya, dengan "siapa yang akan melakukan pekerjaan" memberikan suara yang menentukan. Yang sekarang setidaknya sebagian diperdebatkan; Saya telah melakukan pekerjaan di JuliaParser dan saya akan bersedia melakukannya di Skema jika orang menyukai ide ini.

Ini adalah posting terakhir saya di utas ini, kecuali jika ada reaksi positif terhadap juliaparser saya yang diretas. Bukan niat saya untuk memaksakan kehendak saya; hanya untuk menyajikan sudut pandang saya.

Saya mendukung makro infix ( a <strong i="6">@m</strong> b => <strong i="8">@m</strong> a b ). Itu tidak berarti saya tidak mengetahui argumen yang menentang. Inilah cara saya merangkum argumen terbaik yang menentang:

Fitur bahasa mulai dari -100. Apa yang ditawarkan makro infix yang mungkin bisa mengatasinya? Sesuai dengan sifatnya, tidak ada yang dapat Anda capai dengan makro infiks yang tidak dapat dicapai dengan makro awalan.

Tanggapan saya adalah: Julia pertama-tama adalah bahasa untuk programmer STEM. Matematikawan, insinyur, ahli statistik, fisikawan, ahli biologi, orang yang belajar mesin, ahli kimia, ahli ekonometrika... Dan satu hal yang saya pikir sebagian besar dari mereka sadari adalah kegunaan notasi yang baik. Untuk mengambil contoh yang saya kenal dalam statistik: menambahkan variabel acak independen setara dengan menggulung PDF, atau bahkan mengonversi turunan CDF, tetapi sering kali mengekspresikan sesuatu menggunakan yang pertama bisa menjadi urutan besarnya lebih ringkas dan dapat dimengerti daripada yang terakhir .

Infix versus prefix versus postfix, sampai taraf tertentu, adalah masalah selera. Tetapi ada juga alasan obyektif untuk memilih infiks dalam banyak kasus. Sedangkan prefiks dan postfix menyebabkan endapan yang tidak dapat dicerna dari operator back-to-back seperti yang membuat programmer Forth terdengar seperti politisi Jerman, atau yang membuat programmer Lisp terdengar seperti karikatur Chomskian, infix menempatkan operator di tempat yang sering kali paling kognitif. tempat alami, sedekat mungkin dengan semua operan mereka. Ada alasan mengapa tidak ada orang yang menulis makalah matematika di Forth, dan mengapa matematikawan Jerman pun menggunakan operator infiks saat menulis persamaan.

Ya, makro infix dapat digunakan untuk menulis kode yang dikaburkan. Tetapi makro awalan yang ada juga rentan disalahgunakan. Jika tidak disalahgunakan, makro infix dapat menghasilkan kode yang lebih jelas .

  • (a+b <strong i="18">@choose</strong> b) mengalahkan binomial(a+b,b) ;
  • score ~ age + treatment mengalahkan linearDependency(:score, :(age + treatment)) ;
  • domSelect("#logo") @| css "color" "red" @| fadeIn "slow" <strong i="25">@thenApply</strong> addClass "dummy" mengalahkan neraka dari addOneTimeEventListener(fadeIn(css(domSelect("#logo"),"color","red"),"slow"),"done",(obj,evt)->addClass(obj,"dummy")) .

Saya menyadari bahwa ini hanya contoh mainan tetapi saya pikir prinsipnya valid.

Bisakah hal di atas dilakukan dengan literal string tidak standar? Nah, contoh kedua dan ketiga akan berfungsi sebagai NSL. Tetapi masalah dengan NSL adalah bahwa mereka memberi Anda terlalu banyak kebebasan: kecuali jika Anda terbiasa dengan tata bahasa tertentu, tidak ada cara untuk memastikan apakah token NSL itu, apalagi urutan operasinya. Dengan makro infiks, Anda memiliki cukup kebebasan untuk melakukan semua contoh di atas, tetapi tidak terlalu banyak sehingga tidak jelas dalam membaca kode "baik" apa token itu dan ke mana tanda kurung tersirat.

Itu membutuhkan hal-hal tertentu untuk dipindahkan dari hal yang tidak diketahui ke hal yang tidak diketahui. Dan sayangnya, tidak ada mekanisme untuk melakukan ini. Argumen Anda membutuhkan struktur yang tidak ada.

Sekarang <| adalah asosiatif kanan (#24153), apakah proposal a |>op<| b awal berfungsi?

Saya telah membuat paket untuk peretasan yang disebutkan oleh Steven di https://github.com/JuliaLang/julia/pull/24404#issuecomment -341570934:

Saya bukan berapa banyak operator infix potensial yang terpengaruh ini, tetapi saya sangat ingin menggunakan <~ . Pengurai tidak akan bekerja sama -- bahkan jika saya memberi spasi dengan hati-hati, ia ingin a <~ b berarti a < (~b) .

<- memiliki masalah yang sama.

Maaf jika ini sudah dicakup oleh ini atau masalah lain, tetapi saya tidak dapat menemukannya.

Kami berpotensi membutuhkan spasi di a < ~b ; kami telah menambahkan aturan seperti itu sebelumnya. Kemudian kita dapat menambahkan <- dan <~ sebagai operator infix.

Terima kasih @JeffBezanson , itu akan luar biasa! Apakah ini kasus khusus, atau aturan yang lebih umum? Saya yakin ada beberapa detail dalam aturan yang memungkinkan lebih banyak operator infiks, memberikan kode yang jelas dan dapat diprediksi, dan memecah kode yang ada sesedikit mungkin. Bagaimanapun, saya menghargai bantuan dan respons cepat. Selamat Tahun Baru!

Jika a <~ b akan berbeda dari a < ~b Saya ingin melihat a =+ 1 sebagai kesalahan (atau setidaknya peringatan)

Saya tahu ini adalah diskusi yang cukup lama, dan pertanyaan yang diajukan diajukan beberapa waktu lalu, tetapi saya pikir itu layak untuk dijawab:

Sekarang <| adalah asosiatif kanan (#24153), apakah proposal a |>op<| b awal berfungsi?

Tidak, sayangnya, |> masih diutamakan. Pembaruan yang dilakukan membuatnya, jika Anda mendefinisikan <|(a,b)=a(b) , maka Anda dapat berhasil melakukan a<|b<|c untuk mendapatkan a(b(c)) ... tetapi ini adalah konsep yang berbeda.

Beku selama 2 tahun, komentar dan komit 2 dan 5 hari yang lalu !

Lihat Dokumen operator biner yang dapat disesuaikan f45b6be

Apakah halaman ini membantu?
0 / 5 - 0 peringkat