Bagaimana cara menggunakan Js.Option.map?

Untuk kode ini:

  // val map : ('a -> 'b [@bs]) -> 'a option -> 'b option
  let optTest: Js.Option.t(int) = Js.Option.map(x => x, Js.Option.some(1));

Saya mendapatkan kesalahan berikut:

  This expression should not be a function, the expected type is (. 'a) => 'b

dimana x => x berwarna merah. Saya benar-benar bingung, mengapa map tidak berfungsi? Dari tanda tangan tipenya sepertinya saya menggunakannya dengan benar, namun kompiler mengatakan argumen pertama tidak seharusnya berupa fungsi?


person menfon    schedule 01.02.2020    source sumber


Jawaban (1)


Jawaban singkat - gunakan Belt.Option.map alih-alih:

let optTest: option(int) = Belt.Option.map(Some(1), x => x);

Jawaban panjang:

Namespace Js sebagian besar ditujukan untuk pengikatan ke API standar JavaScript. Dan meskipun Js.Option karena alasan historis disertakan dalam namespace ini, konvensi yang digunakan dalam namespace Js masih menggunakan ikatan yang sangat tipis.

Tipe yang Anda lihat untuk fungsi panggilan balik di dokumentasi, 'a -> 'b [@bs], dan tipe yang Anda lihat di pesan kesalahan, (. 'a) => 'b, adalah tipe yang persis sama. Tapi yang pertama ada dalam sintaks OCaml sedangkan yang kedua ada di Reason, dan juga dipercantik agar terlihat tidak terlalu menyinggung. Apa pun yang terjadi, masalahnya adalah Anda memberikannya fungsi biasa padahal ia mengharapkan fungsi aneh lainnya.

Fungsi aneh lainnya disebut fungsi uncurried. Disebut demikian karena fungsi "normal" di Reason bersifat kari, sedangkan fungsi JavaScript tidak. Oleh karena itu, fungsi yang tidak disimpan pada dasarnya hanyalah fungsi JavaScript asli, yang terkadang perlu Anda tangani karena Anda mungkin menerimanya atau perlu meneruskannya ke fungsi JavaScript tingkat tinggi, seperti yang ada di namespace Js.

Jadi bagaimana Anda membuat fungsi uncurried di Reason? Cukup tambahkan ., seperti pada tipe:

let optTest: option(int) = Js.Option.map((.x) => x, Some(1);

Atau jika Anda ingin melakukannya tanpa gula (yang tidak Anda lakukan, tetapi demi kelengkapan):

let optTest: option(int) = Js.Option.map([@bs] x => x, Some(1);

Tambahan:

Anda mungkin memperhatikan bahwa saya telah mengganti Js.Option.t dan Js.Option.some dalam contoh Anda dengan option dan Some. Itu karena mereka adalah orang-orang primitif yang sebenarnya. Tipe option pada dasarnya didefinisikan sebagai

type option('a) =
  | Some('a)
  | None

dan tersedia di mana-mana.

Js.Option.t('a) (dan Belt.Option.t('a)) hanyalah sebuah alias. Dan Js.Option.some hanyalah fungsi praktis yang tidak ada padanannya di Belt.Option. Mereka sebagian besar hanya ada di sana untuk konsistensi, dan Anda biasanya harus menggunakan konstruktor tipe dan varian yang sebenarnya.

person glennsl    schedule 01.02.2020
comment
Terima kasih atas jawaban yang lengkap. Saya baru belajar alasan dan membaca penjelasan Anda sangat membantu saya untuk memahaminya dengan lebih baik. Sangat menyenangkan ketika seseorang berupaya membantu komunitas. - person Dmitry Biletskyy; 02.02.2020