Js.Option.map ใช้งานอย่างไร?

สำหรับรหัสนี้:

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

ฉันได้รับข้อผิดพลาดดังต่อไปนี้:

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

โดยที่ x => x เป็นสีแดง ฉันสับสนจริงๆ ทำไม map ไม่ทำงาน จากลายเซ็นประเภทดูเหมือนว่าฉันใช้มันอย่างถูกต้อง แต่คอมไพเลอร์บอกว่าอาร์กิวเมนต์แรกไม่ควรจะเป็นฟังก์ชัน


person menfon    schedule 01.02.2020    source แหล่งที่มา


คำตอบ (1)


คำตอบสั้นๆ - ใช้ Belt.Option.map แทน:

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

คำตอบยาว:

เนมสเปซ Js มีไว้สำหรับการเชื่อมโยงกับ API มาตรฐานของ JavaScript เป็นส่วนใหญ่ และในขณะที่ Js.Option ด้วยเหตุผลทางประวัติศาสตร์ถูกรวมไว้ในเนมสเปซนี้ รูปแบบที่ใช้ใน Js ยังคงเป็นการเชื่อมโยงที่บางมาก

ประเภทที่คุณเห็นสำหรับฟังก์ชันการติดต่อกลับในเอกสารประกอบ 'a -> 'b [@bs] และประเภทที่คุณเห็นในข้อความแสดงข้อผิดพลาด (. 'a) => 'b นั้นเป็นประเภทเดียวกันทุกประการ แต่อย่างแรกอยู่ในไวยากรณ์ของ OCaml ในขณะที่อย่างหลังอยู่ในเหตุผล และยังถูกปรับให้ดูน่ารังเกียจน้อยลงอีกด้วย ไม่ว่าจะด้วยวิธีใด ปัญหาคือคุณส่งผ่านฟังก์ชันธรรมดาไปเมื่อมันคาดหวังว่าจะมีฟังก์ชันแปลกๆ อีกแบบหนึ่ง

ฟังก์ชันแปลกๆ อีกประเภทหนึ่งเรียกว่าฟังก์ชัน uncurried ที่ถูกเรียกอย่างนั้นเพราะว่าฟังก์ชัน "ปกติ" ใน Reason เป็นแบบ Curried ในขณะที่ฟังก์ชัน JavaScript ไม่ใช่ ดังนั้นฟังก์ชัน uncurried จึงเป็นเพียงฟังก์ชัน JavaScript ดั้งเดิม ซึ่งบางครั้งคุณจำเป็นต้องจัดการด้วย เนื่องจากคุณอาจได้รับฟังก์ชันหนึ่งหรือจำเป็นต้องส่งฟังก์ชันหนึ่งไปยังฟังก์ชัน JavaScript ที่มีลำดับสูงกว่า เช่น ในเนมสเปซ Js

แล้วคุณจะสร้างฟังก์ชันที่ไม่มีการเปลี่ยนแปลงในเหตุผลได้อย่างไร? เพียงเพิ่ม . เช่นเดียวกับในประเภท:

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

หรือถ้าคุณต้องการทำโดยไม่ใส่น้ำตาล (ซึ่งคุณไม่ต้องการ แต่เพื่อความสมบูรณ์):

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

ภาคผนวก:

คุณอาจสังเกตเห็นว่าฉันได้แทนที่ Js.Option.t และ Js.Option.some ในตัวอย่างของคุณด้วย option และ Some นั่นเป็นเพราะว่าสิ่งเหล่านั้นคือสิ่งดั้งเดิมที่แท้จริง ประเภท option ถูกกำหนดโดยพื้นฐานแล้วเป็น

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

และสามารถใช้ได้ทุกที่

Js.Option.t('a) (และ Belt.Option.t('a)) เป็นเพียงนามแฝง และ Js.Option.some เป็นเพียงฟังก์ชันอำนวยความสะดวกซึ่งไม่มีค่าใดเทียบเท่าใน Belt.Option ส่วนใหญ่จะมีไว้เพื่อความสอดคล้อง และโดยปกติคุณควรใช้ประเภทจริงและตัวสร้างตัวแปรแทน

person glennsl    schedule 01.02.2020
comment
ขอบคุณสำหรับคำตอบที่สมบูรณ์เช่นนี้ ฉันแค่เรียนรู้เหตุผลและการอ่านคำอธิบายของคุณช่วยให้ฉันเข้าใจดีขึ้นมาก เป็นเรื่องดีเมื่อมีคนพยายามช่วยเหลือชุมชน - person Dmitry Biletskyy; 02.02.2020