Atas saran @ amon, inilah jawaban yang lebih monadik. Ini adalah versi yang sangat matang, di mana Anda harus menerima beberapa asumsi:
fungsi "unit" atau "return" adalah konstruktor kelas
operasi "bind" terjadi pada waktu kompilasi, jadi itu disembunyikan dari doa
fungsi "action" juga terikat ke kelas pada waktu kompilasi
walaupun kelasnya generik dan membungkus sembarang kelas E, saya pikir itu sebenarnya berlebihan dalam hal ini. Tetapi saya membiarkannya sebagai contoh dari apa yang dapat Anda lakukan.
Dengan pertimbangan tersebut, monad diterjemahkan ke dalam kelas pembungkus yang lancar (meskipun Anda memberikan banyak fleksibilitas yang akan Anda dapatkan dalam bahasa yang murni fungsional):
public class RepositoryLookup<E> {
private String source;
private E answer;
private Exception exception;
public RepositoryLookup<E>(String source) {
this.source = source;
}
public RepositoryLookup<E> fetchElement() {
if (answer != null) return this;
if (! exception instanceOf NotFoundException) return this;
try {
answer = lookup(source);
}
catch (Exception e) {
exception = e;
}
return this;
}
public RepositoryLookup<E> orFetchSimilarElement() {
if (answer != null) return this;
if (! exception instanceOf NotFoundException) return this;
try {
answer = lookupVariation(source);
}
catch (Exception e) {
exception = e;
}
return this;
}
public RepositoryLookup<E> orFetchParentElement() {
if (answer != null) return this;
if (! exception instanceOf NotFoundException) return this;
try {
answer = lookupParent(source);
}
catch (Exception e) {
exception = e;
}
return this;
}
public boolean failed() {
return exception != null;
}
public Exception getException() {
return exception;
}
public E getAnswer() {
// better to check failed() explicitly ;)
if (this.exception != null) {
throw new IllegalArgumentException(exception);
}
// TODO: add a null check here?
return answer;
}
}
(ini tidak akan dikompilasi ... detail tertentu dibiarkan belum selesai untuk menjaga sampel tetap kecil)
Dan doa akan terlihat seperti ini:
Repository<String> repository = new Repository<String>(x);
repository.fetchElement().orFetchParentElement().orFetchSimilarElement();
if (repository.failed()) {
throw new IllegalArgumentException(repository.getException());
}
System.err.println("Got " + repository.getAnswer());
Perhatikan bahwa Anda memiliki fleksibilitas untuk menyusun operasi "ambil" sesuka Anda. Itu akan berhenti ketika mendapat jawaban atau pengecualian selain tidak ditemukan.
Saya melakukan ini dengan sangat cepat; itu tidak benar, tetapi mudah-mudahan menyampaikan gagasan itu
NotFoundException
sesuatu yang benar-benar luar biasa?