Pencocokan pola idiomatik setara di Jawa

9

Saya sedang membangun simulator yang mem-parsing beberapa peristiwa dari STDINdan "menjalankan" mereka. Latar belakang saya sebagian besar pemrograman fungsional hari ini, jadi sepertinya wajar untuk melakukan sesuatu seperti ini:

data Event = Thing1 String Int | Thing2 Int | Thing3 String String Int
Parse :: String -> [Event]
Simulate :: [Event] -> [Result]

di mana akan mensimulasikan

case event
  of Thing1 a b => compute for thing one
   | Thing2 a => compute for thing two

dll. Apa cara idiomatis untuk melakukan hal semacam ini di Jawa? Googling telah menunjuk saya ke arah kelas bersarang dan pola pengunjung, tetapi itu tampaknya agak berat dalam upaya saya. Penghapusan tipe sepertinya melawan saya, sulit. Bisakah Anda menunjukkan kepada saya garis besar tentang apa yang akan dilakukan dengan benar?

closeparen
sumber
1
Mungkin tergantung pada jenisnya sampai batas tertentu. Bisakah Anda jelaskan secara singkat apa yang dimaksud dengan acara dan anggota int / stringnya? Misalnya, apakah Eventtipe secara konseptual sama dengan memiliki satu Intdan dua Maybe Strings?
Ixrec
1
Apakah Java bahasa yang Anda inginkan atau Anda harus bekerja dengan?
Thomas Junk
Pencocokan pola mungkin fitur masa depan di Java 1x yang dijelaskan dalam JEP 305 .
tsh

Jawaban:

11

Penulis 'Pemrograman Fungsional di Scala' memberikan ilustrasi yang bagus tentang yang terbaik yang dapat dicapai di Jawa dengan cara yang aman:

http://blog.higher-order.com/blog/2009/08/21/structural-pattern-matching-in-java/

Pada dasarnya, ini menggunakan pengkodean Gereja dari kasus-kasus untuk memastikan bahwa kompiler akan mengeluh jika ada yang hilang.

Rincian tidak mudah diringkas dan memang begitu baik dibahas dalam artikel tersebut bahwa tidak ada gunanya mereproduksi mereka di sini (yang ini hyperlink apa untuk benar?).

NietzscheanAI
sumber
Terima kasih, ini kurang lebih apa yang saya cari. Pengunjung akhirnya berhasil dengan cukup baik untuk kasus ini, tetapi saya kemungkinan akan menggunakan contoh Gereja di masa depan.
closeparen
2
Saya pikir itu pintar, tapi saya tidak yakin itu idiomatik
Brian Agnew
Setara idiomatis adalah pengiriman ganda, di mana Anda melewati satu objek t.matchdengan tiga metode daripada melewati tiga fungsi. (artikel yang ditautkan membingungkan Pola pengunjung dengan pengiriman ganda - pengunjung adalah pola untuk mengabstraksi iterasi melalui jaringan, bukan untuk memilih pola)
Pete Kirkham
Pengiriman ganda adalah salah satu cara menerapkan pola Pengunjung. Saya tidak tahu apa yang Anda maksud dengan 'mengabstraksi iterasi melalui jaringan' - itu bukan frasa yang digunakan dalam definisi Pengunjung GoF.
NietzscheanAI
Saya berjuang dengan blog / artikel ini karena dia mulai dengan ini dalam contoh 'buruknya': di public static int depth(Tree t)mana dia menggunakan rantai jika sebuah instance ketika cara 'benar' untuk melakukan ini di Jawa adalah dengan mendefinisikan antarmuka dengan metode: public int depth()dan gunakan polimorfisme. Sepertinya manusia jerami.
JimmyJames
4

Apa cara idiomatis untuk melakukan hal semacam ini di Jawa?

Sebenarnya tidak ada hal seperti itu, mengingat bahwa Java (bahasa) pada dasarnya penting.

Jika Anda dapat menjalankan JVM, tetapi tidak terbatas pada bahasa Java , Anda bisa menyelidiki Scala, yang akan mencapai sesuatu seperti di atas menggunakan pencocokan pola .

Kalau tidak, saya pikir Anda tidak cocok dengan berbagai kasus dan metode panggilan secara manual, atau mungkin mendefinisikan subtipe 'Peristiwa' dan menggunakan polimorfisme untuk memanggil metode tertentu untuk setiap subtipe.

Brian Agnew
sumber
Saya pikir paragraf terakhir Anda mengenai paku di kepala. Pendekatan idiomatik untuk ini di Jawa adalah dengan menggunakan polimorfisme. Memiliki Acara menjadi antarmuka dengan metode yang sesuai, dan Thing1, Thing2 dan Thing3 menjadi implementasi dari antarmuka itu. Itu membagi kode berdasarkan jenis daripada berdasarkan fungsi, tapi kemudian pada dasarnya itu adalah titik OOP, bukan?
Jules
Menjadi imperatif Jawa tidak penting. Java dapat (dan harus) mengintegrasikan tipe jumlah, tetapi tidak.
Gardenhead
1

Lihatlah https://github.com/johnlcox/motif yang merupakan pustaka "pencocokan pola" seperti Scala untuk Java 8.

Tidak sebagus ML / Erlang / Haskell, tetapi masih terlihat jauh lebih deklaratif daripada kebanyakan.

9000
sumber
0

Anda bisa menggunakan enum dan antarmuka, mengganti metode simulasi, seperti ini:

interface Event {
  void simulate()
}

enum MyEvents implements Event {
  THING1 {
    @Override
    void simulate() {
    //...
    }
  },
  THING2 {
    @Override
    void simulate() {
    //...
    }
  },
}

Katakanlah Anda punya Event event. Kemudian Anda dapat menggunakannya dalam salah satu dari dua cara:

event.simulate();

atau

switch(event) {
  case THING1:
    //..
    break;
  case THING2:
    break;
}

Tetapi konstruktor dipanggil secara otomatis oleh JVM, jadi untuk juga menyimpan parameter di sana Anda harus menambahkan properti dengan accessors dll.

Atau, Anda bisa membuat kode acara Anda sebagai string konstan dan menggunakan switchkonstruksi, dalam hal ini Anda akan melakukannya

string event = args[0];
switch(event){
  case THING1:
    int a = args[1];
    //...
    break;
  case THING2:
    int a = args[1];
    int b = args[2];
    break;
}

dll. Tapi ya, tidak ada yang asli yang langsung meniru pencocokan pola :(

jasiek.miko
sumber
Saya tidak yakin mengapa Anda menggunakan enum di sini daripada kelas - apa manfaat dari enum?
Jules
Karena dengan begitu Anda juga dapat menggunakannya dalam pernyataan sakelar, yang membuatnya sedikit lebih mirip pencocokan pola
jasiek.miko
menambahkan itu sekarang.
jasiek.miko
0

Pola pengunjung atau ekuivalen penyandian gerejanya adalah cara yang harus ditempuh. Ini agak bertele-tele di Jawa, tapi semoga alat seperti Derive4J (prosesor anotasi yang saya pertahankan) atau Adt4J dapat menghasilkan boilerplate. Dengan menggunakan alat seperti itu, contoh Anda menjadi:

import java.util.function.Function;
import org.derive4j.Data;

@Data
public abstract class Event {

  interface Cases<X> {
    X Thing1(String s, int i);
    X Thing2(int i);
    X Thing3(String s, String s2, int i);
  }

  abstract <X> X match(Cases<X> cases);

  static Function<Event, Result> Simulate =
      Events.cases().
          Thing1( (s, i    ) -> computeForThingOne(s, i)       ).
          Thing2( (i       ) -> computeForThingTwo(i)          ).
          Thing3( (s, s2, i) -> computeForThingThree(s, s2, i) );

}

Derive4J menghasilkan kelas Acara yang menyediakan sintaks pencocokan pola yang fasih (dengan pemeriksaan lengkap bahwa semua kasus ditangani).

JbGi
sumber
Bisakah Anda mengklarifikasi afiliasi Anda dengan proyek di pos Anda (lihat, stackoverflow.com/help/promotion ).
Benni