Saat membuat klien untuk API web di C #, saya mengalami masalah terkait null
dengan nilai yang mewakili dua hal yang berbeda:
- tidak ada , mis.
foo
mungkin atau mungkin tidakbar
- tidak diketahui : secara default respons API hanya mencakup subset properti, Anda harus menunjukkan properti tambahan yang Anda inginkan. Jadi tidak diketahui berarti bahwa properti itu tidak diminta dari API.
Setelah beberapa pencarian saya menemukan tentang jenis Maybe (atau Option), bagaimana ini digunakan dalam bahasa fungsional dan bagaimana "memecahkan" masalah null dereferencing dengan memaksa pengguna untuk berpikir tentang kemungkinan tidak adanya nilai. Namun, semua sumber yang saya temui berbicara tentang mengganti null dengan Maybe . Saya memang menemukan beberapa menyebutkan logika bernilai tiga , tapi saya tidak sepenuhnya memahaminya dan sebagian besar menyebutkannya dalam konteks "itu hal yang buruk".
Saya sekarang bertanya-tanya apakah masuk akal untuk memiliki konsep null dan Maybe , masing-masing untuk mewakili yang tidak diketahui dan tidak sama sekali . Apakah ini logika tiga nilai yang saya baca, atau apakah itu memiliki nama lain? Atau apakah cara yang dimaksudkan untuk bersarang dalam Maybe in a Maybe?
null
. Itu adalah ide yang benar-benar rusak.M M x
danM x
harus memiliki semantik yang sama.Maybe a
sama dengan , secara semantik, sama dengan , dan isomorfik untuk mengetik dari jawaban @Andej. Anda dapat mendefinisikan turunan monad Anda sendiri untuk jenis ini juga dan karenanya menggunakan kombinator monad yang berbeda. a + 1 + 1Maybe Maybe a
UserInput a
M (M x)
danM x
harus memiliki semantik yang sama". AmbilM = List
contoh: daftar daftar tidak sama dengan daftar. KetikaM
adalah monad, ada transformasi (yaitu monad perkalian) dariM (M x)
keM x
yang menjelaskan hubungan antara mereka, tetapi mereka tidak memiliki "semantik yang sama".Jawaban:
The
null
nilai sebagai hadiah bawaan di mana-mana hanya ide yang sangat rusak , jadi lupa tentang itu.Anda harus selalu memiliki konsep yang paling tepat menggambarkan data aktual Anda. Jika Anda memerlukan jenis yang menunjukkan "tidak dikenal", "tidak ada", dan "nilai", Anda harus memiliki itu. Tetapi jika itu tidak sesuai dengan kebutuhan Anda yang sebenarnya maka Anda seharusnya tidak melakukannya. Merupakan ide bagus untuk melihat apa yang digunakan orang lain dan apa yang mereka usulkan, tetapi Anda tidak harus mengikuti mereka secara membabi buta.
Orang-orang yang merancang perpustakaan standar mencoba menebak pola penggunaan umum, dan mereka biasanya melakukannya dengan baik, tetapi jika ada hal tertentu yang Anda butuhkan, Anda harus mendefinisikannya sendiri. Misalnya, di Haskell, Anda dapat mendefinisikan:
Bahkan mungkin Anda harus menggunakan sesuatu yang lebih deskriptif yang lebih mudah diingat:
Anda dapat menentukan 10 jenis yang akan digunakan untuk skenario yang berbeda. Kekurangannya adalah Anda tidak akan memiliki fungsi perpustakaan yang sudah ada sebelumnya (seperti yang ada
Maybe
), tetapi ini biasanya menjadi detail. Tidak terlalu sulit untuk menambahkan fungsionalitas Anda sendiri.sumber
Sejauh yang saya tahu, nilai
null
dalam C # adalah nilai yang mungkin untuk beberapa variabel, tergantung pada jenisnya (apakah saya benar?). Misalnya, contoh beberapa kelas. Untuk jenis lainnya (sepertiint
,,bool
dll) Anda dapat menambahkan nilai pengecualian ini dengan mendeklarasikan variabel denganint?
ataubool?
sebagai gantinya (ini persis seperti yang dilakukan olehMaybe
konstruktor, seperti yang akan saya jelaskan selanjutnya).The
Maybe
tipe konstruktor dari pemrograman fungsional menambahkan ini nilai pengecualian baru untuk datatype tertentu. Jadi jikaInt
adalah tipe bilangan bulat atauGame
jenis keadaan permainan, makaMaybe Int
semua bilangan bulat ditambah nilai nol (terkadang disebut tidak ada ). Sama untukMaybe Game
. Di sini, tidak ada tipe yang datang dengannull
nilai. Anda menambahkannya saat Anda membutuhkannya.IMO, pendekatan terakhir ini adalah yang terbaik untuk bahasa pemrograman apa pun.
sumber
Maybe
dan menjatuhkannull
seluruhnya?isinstance
pengujian. Scala juga memiliki pencocokan pola yang "tepat", dan C♯ sebenarnya baru saja mendapatkan pola yang sederhana juga.final
(untuk kelas yang tidak dapat diwarisi dari), ia juga memilikisealed
, untuk kelas yang dapat diperluas hanya dalam unit kompilasi yang sama . Ini berarti bahwa kompiler dapat secara statis mengetahui semua subkelas yang mungkin (asalkan semuanya adalah diri mereka sendirisealed
ataufinal
) dan dengan demikian melakukan pemeriksaan kelengkapan untuk kecocokan pola, yang tidak mungkin secara statis untuk bahasa dengan pemuatan kode runtime dan pewarisan yang tidak terbatas.int??
ilegal di C #.Jika Anda dapat mendefinisikan serikat jenis, seperti
X or Y
, dan jika Anda memiliki jenis bernamaNull
yang hanya mewakilinull
nilai (dan tidak ada yang lain), maka untuk jenis apa punT
,T or Null
sebenarnya tidak jauh berbedaMaybe T
. Satu-satunya masalah dengannull
adalah ketika memperlakukan bahasa tipeT
sebagaiT or Null
implisit, membuatnull
nilai yang valid untuk setiap jenis (kecuali tipe primitif dalam bahasa yang memiliki mereka). Inilah yang terjadi misalnya di Jawa di mana fungsi yang mengambilString
juga menerimanull
.Jika Anda memperlakukan tipe sebagai set nilai dan
or
sebagai gabungan set, maka(T or Null) or Null
mewakili set nilaiT ∪ {null} ∪ {null}
, yang sama denganT or Null
. Ada kompiler yang melakukan analisis semacam ini (SBCL). Seperti yang dikatakan dalam komentar, Anda tidak dapat dengan mudah membedakan antaraMaybe T
danMaybe Maybe T
ketika Anda melihat jenis sebagai domain (di sisi lain, tampilan itu cukup berguna untuk program yang diketik secara dinamis). Tetapi Anda juga bisa menjaga tipe sebagai ekspresi aljabar, di mana(T or Null) or Null
mewakili beberapa level Maybes.sumber
Maybe (Maybe X)
tidak sama denganMaybe X
.Nothing
tidak sama denganJust Nothing
. BerkembangMaybe (Maybe X)
denganMaybe X
membuat tidak mungkin untuk mengobati secaraMaybe _
polimorfik.Anda perlu mencari tahu apa yang ingin Anda ungkapkan, dan kemudian menemukan cara bagaimana mengekspresikannya.
Pertama, Anda memiliki nilai dalam domain masalah Anda (seperti angka, string, catatan pelanggan, boolean, dll). Kedua, Anda memiliki beberapa nilai generik tambahan di atas nilai domain masalah Anda: Misalnya "tidak ada" (ketiadaan nilai yang diketahui), "tidak diketahui" (tidak ada pengetahuan tentang ada atau tidaknya suatu nilai), tidak disebutkan adalah " sesuatu "(pasti ada nilainya, tapi kami tidak tahu yang mana). Mungkin Anda bisa memikirkan situasi lain.
Jika Anda ingin dapat mewakili semua nilai plus tiga nilai tambahan ini, Anda akan membuat enum dengan kasus "tidak ada", "tidak diketahui", "sesuatu", dan "nilai" dan pergi dari sana.
Dalam beberapa bahasa beberapa kasus lebih sederhana. Sebagai contoh, di Swift Anda memiliki untuk setiap jenis T jenis "opsional T" yang memiliki nilai yang mungkin nihil ditambah semua nilai T. Ini memungkinkan Anda menangani banyak situasi dengan mudah, dan sangat cocok jika Anda memiliki "tidak ada" dan " nilai". Anda dapat menggunakannya jika Anda memiliki "tidak dikenal" dan "nilai". Anda tidak dapat menggunakannya jika Anda perlu menangani "tidak ada", "tidak diketahui" dan "nilai". Bahasa lain mungkin menggunakan "null" atau "mungkin", tapi itu hanya kata lain.
Di JSON, Anda memiliki kamus dengan pasangan kunci / nilai. Di sini, sebuah kunci mungkin saja hilang dari kamus, atau mungkin memiliki nilai nol. Jadi dengan menjelaskan dengan cermat bagaimana barang-barang disimpan, Anda dapat mewakili nilai-nilai umum ditambah dua nilai tambahan.
sumber