หากฟังก์ชันมีชนิดส่งคืนเป็น⊥ ( ชนิดด้านล่าง ) นั่นหมายความว่าจะไม่ส่งคืน มันสามารถยกตัวอย่างเช่นออกหรือโยนทั้งสถานการณ์ธรรมดา
สันนิษฐานว่าถ้าฟังก์ชั่นมีพารามิเตอร์ประเภท⊥มันจะไม่สามารถเรียก (ปลอดภัย) มีเหตุผลใดบ้างในการนิยามฟังก์ชั่นดังกล่าว?
หากฟังก์ชันมีชนิดส่งคืนเป็น⊥ ( ชนิดด้านล่าง ) นั่นหมายความว่าจะไม่ส่งคืน มันสามารถยกตัวอย่างเช่นออกหรือโยนทั้งสถานการณ์ธรรมดา
สันนิษฐานว่าถ้าฟังก์ชั่นมีพารามิเตอร์ประเภท⊥มันจะไม่สามารถเรียก (ปลอดภัย) มีเหตุผลใดบ้างในการนิยามฟังก์ชั่นดังกล่าว?
คำตอบ:
หนึ่งในการกำหนดคุณสมบัติของหรือประเภทที่ว่างเปล่าว่ามีฟังก์ชั่นทุกประเภท ในความเป็นจริงมีฟังก์ชั่นดังกล่าวที่ไม่ซ้ำกันอยู่ ดังนั้นจึงเหมาะสมสำหรับฟังก์ชั่นนี้ในการเป็นส่วนหนึ่งของไลบรารีมาตรฐาน บ่อยครั้งที่มันจะเรียกว่าสิ่งที่ต้องการ (ในระบบที่มี Subtyping นี้อาจได้รับการจัดการโดยเพียงแค่มี⊥เป็นชนิดย่อยของทุกประเภท. แล้วแปลงเป็นนัย. อีกวิธีที่เกี่ยวข้องคือการกำหนด⊥เป็น∀ α . αซึ่งสามารถก็จะinstantiatedประเภทใด ๆ .)absurdabsurd
แน่นอนคุณต้องการที่จะมีฟังก์ชั่นดังกล่าวหรือเทียบเท่าเพราะมันเป็นสิ่งที่ช่วยให้คุณสามารถทำให้การใช้งานฟังก์ชั่นที่ผลิต⊥ตัวอย่างเช่นสมมติว่าฉันได้รับชนิดรวมฉันทำวิเคราะห์กรณีที่เกี่ยวกับมันและในกรณีที่ฉันกำลังจะไปโยนยกเว้นใช้ ⊥ ในกรณีที่ผมจะใช้F : → B โดยรวม, ฉันต้องการค่าของชนิดBดังนั้นฉันต้องการที่จะทำบางสิ่งบางอย่างที่จะเปิด⊥เป็นB นั่นคือสิ่งที่ฉันจะทำabsurd
ที่กล่าวว่ามีไม่มากทั้งเหตุผลที่จะกำหนดฟังก์ชั่นของตัวเองของabsurdตามคำนิยามที่พวกเขาจำเป็นต้องจะเป็นกรณีของ ถึงกระนั้นคุณอาจทำได้หากabsurdไม่มีไลบรารีมาตรฐานหรือคุณต้องการรุ่นเฉพาะประเภทเพื่อช่วยตรวจสอบ / อนุมานประเภท อย่างไรก็ตามคุณสามารถได้อย่างง่ายดายผลิตฟังก์ชั่นที่จะจบลงอินสแตนซ์ชนิดเช่น
ถึงแม้ว่าจะมีไม่มากเหตุผลที่จะเขียนฟังก์ชันดังกล่าวก็ควรโดยทั่วไปยังคงได้รับอนุญาต เหตุผลหนึ่งคือทำให้เครื่องมือ / มาโครการสร้างรหัสง่ายขึ้น
absurdabsurdthrow
เพื่อเพิ่มสิ่งที่ถูกกล่าวถึงเกี่ยวกับฟังก์ชั่นabsurd: ⊥ -> aฉันมีตัวอย่างที่ชัดเจนว่าฟังก์ชั่นนี้มีประโยชน์อย่างไร
พิจารณาประเภทข้อมูล Haskell Free f aซึ่งแสดงถึงโครงสร้างต้นไม้ทั่วไปที่มี fโหนดรูปทรงและใบไม้ที่มีas:
data Free f a = Op (f (Free f a)) | Var a
ต้นไม้เหล่านี้สามารถพับเก็บได้ด้วยฟังก์ชั่นต่อไปนี้:
fold :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b
fold gen alg (Var x) = gen x
fold gen alg (Op x) = alg (fmap (fold gen alg) x)
สั้น ๆ การดำเนินการนี้จะวางalgที่โหนดและgenที่ใบ
ถึงตอนนี้: โครงสร้างข้อมูลแบบเรียกซ้ำทั้งหมดสามารถแสดงได้โดยใช้ประเภทข้อมูลคงที่ ใน Haskell นี่คือFix fและมันสามารถกำหนดเป็นtype Fix f = Free f ⊥(เช่นต้นไม้ที่มีfโหนดรูปทรงและไม่มีใบด้านนอกของ functor f) ตามเนื้อผ้าโครงสร้างนี้มีเท่าที่เรียกว่าcata:
cata :: Functor f => (f a -> a) -> Fix f -> a
cata alg x = fold absurd alg x
ซึ่งทำให้ใช้งานได้อย่างไร้สาระ: เนื่องจากต้นไม้ไม่สามารถมีใบไม้ได้ (เนื่องจาก⊥ไม่มีคนอาศัยอยู่นอกจากundefined) มันจึงไม่มีทางเป็นไปได้ที่จะใช้สิ่งgenเหล่านี้และabsurdแสดงให้เห็นว่า!
ประเภทด้านล่างเป็นประเภทย่อยของประเภทอื่น ๆ ทุกประเภทซึ่งอาจเป็นประโยชน์อย่างมากในทางปฏิบัติ ตัวอย่างเช่นประเภทของNULLรุ่นที่ปลอดภัยในเชิงทฤษฎีของ C จะต้องเป็นประเภทย่อยของตัวชี้ประเภทอื่น ๆ ทุกประเภทไม่เช่นนั้นคุณจะไม่สามารถกลับไปNULLที่ตำแหน่งที่char*คาดไว้ ในทำนองเดียวกันประเภทของundefinedJavaScript ปลอดภัยในทางทฤษฎีจะต้องเป็นประเภทย่อยของทุกประเภทอื่น ๆ ในภาษา
exit()throw()IntIntexit()
NULLชนิดของหน่วยไม่ได้แตกต่างจาก⊥ซึ่งเป็นประเภทที่ว่างเปล่า?
void*คุณจะต้องมีประเภทที่เฉพาะเจาะจงที่สามารถนำมาใช้สำหรับประเภทตัวชี้ใด ๆ
มีอยู่ครั้งหนึ่งที่ฉันนึกถึงและมันเป็นสิ่งที่ได้รับการพิจารณาว่าเป็นการพัฒนาภาษาโปรแกรม Swift
สวิฟท์มีmaybeMonad สะกดหรือOptional<T> T?มีหลายวิธีในการโต้ตอบกับมัน
คุณสามารถใช้การคลายแบบมีเงื่อนไขเช่น
if let nonOptional = someOptional {
print(nonOptional)
}
else {
print("someOptional was nil")
}
คุณสามารถใช้map, flatMapการแปลงค่า
!ของประเภท(T?) -> T) เพื่อแกะเนื้อหาออกมาอย่างรุนแรงตัวดำเนินการ nil-coalescing ( ??ชนิด(T?, T) -> T) เพื่อรับค่าหรือใช้ค่าเริ่มต้น:
let someI = Optional(100)
print(someI ?? 123) => 100 // "left operand is non-nil, unwrap it.
let noneI: Int? = nil
print(noneI ?? 123) // => 123 // left operand is nil, take right operand, acts like a "default" value
ขออภัยไม่มีวิธีรัดกุมในการพูดว่า "แกะหรือโยนข้อผิดพลาด" หรือ "แกะหรือขัดข้องด้วยข้อความแสดงข้อผิดพลาดที่กำหนดเอง" สิ่งที่ต้องการ
let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")
ไม่ได้รวบรวมเนื่องจากfatalErrorมีประเภท() -> Never( ()คือVoidประเภทหน่วยNeverของ Swift คือประเภทด้านล่างของ Swift) เรียกมันว่าผลิตNeverซึ่งไม่ได้เข้ากันได้กับที่คาดว่าจะเป็นตัวถูกดำเนินการทางด้านขวาของT??
ในความพยายามที่จะแก้ไขปัญหานี้Swift Evolution propsoal SE-0217- ตัวดำเนินการ“ Unwrap or Die”ถูกนำเสนอ ในที่สุดมันก็ถูกปฏิเสธแต่มันก็ทำให้ความสนใจในการNeverเป็นประเภทย่อยทุกประเภท
หากNeverทำให้เป็นประเภทย่อยของทุกประเภทแล้วตัวอย่างก่อนหน้านี้จะสามารถคอมไพล์ได้:
let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")
เพราะการเรียกร้องของเว็บไซต์??มีประเภท(T?, Never) -> Tซึ่งจะเข้ากันได้กับลายเซ็นของ(T?, T) -> T??
Swift มีประเภท "ไม่เคย" ซึ่งดูเหมือนว่าจะเป็นประเภทล่าง: ฟังก์ชั่นที่ประกาศให้คืนไม่สามารถย้อนกลับได้ฟังก์ชันที่ใช้พารามิเตอร์ประเภทไม่สามารถเรียกได้
สิ่งนี้มีประโยชน์ในการเชื่อมต่อกับโปรโตคอลซึ่งอาจมีข้อ จำกัด เนื่องจากระบบประเภทของภาษาที่คลาสจะต้องมีฟังก์ชั่นบางอย่าง แต่ไม่มีความต้องการที่จะเรียกใช้ฟังก์ชั่นนี้และไม่ต้องการสิ่งที่ประเภทอาร์กิวเมนต์ อยากจะเป็น.
สำหรับรายละเอียดคุณควรดูที่โพสต์ที่ใหม่กว่าในรายชื่อผู้รับจดหมายอย่างรวดเร็ว
(x ? 3 : throw new Exception())ได้รับการแทนที่เพื่อการวิเคราะห์ด้วยบางสิ่งที่มากกว่า(x ? 3 : absurd(throw new Exception()))?