หากฟังก์ชันมีชนิดส่งคืนเป็น⊥ ( ชนิดด้านล่าง ) นั่นหมายความว่าจะไม่ส่งคืน มันสามารถยกตัวอย่างเช่นออกหรือโยนทั้งสถานการณ์ธรรมดา
สันนิษฐานว่าถ้าฟังก์ชั่นมีพารามิเตอร์ประเภท⊥มันจะไม่สามารถเรียก (ปลอดภัย) มีเหตุผลใดบ้างในการนิยามฟังก์ชั่นดังกล่าว?
หากฟังก์ชันมีชนิดส่งคืนเป็น⊥ ( ชนิดด้านล่าง ) นั่นหมายความว่าจะไม่ส่งคืน มันสามารถยกตัวอย่างเช่นออกหรือโยนทั้งสถานการณ์ธรรมดา
สันนิษฐานว่าถ้าฟังก์ชั่นมีพารามิเตอร์ประเภท⊥มันจะไม่สามารถเรียก (ปลอดภัย) มีเหตุผลใดบ้างในการนิยามฟังก์ชั่นดังกล่าว?
คำตอบ:
หนึ่งในการกำหนดคุณสมบัติของหรือประเภทที่ว่างเปล่าว่ามีฟังก์ชั่นทุกประเภท ในความเป็นจริงมีฟังก์ชั่นดังกล่าวที่ไม่ซ้ำกันอยู่ ดังนั้นจึงเหมาะสมสำหรับฟังก์ชั่นนี้ในการเป็นส่วนหนึ่งของไลบรารีมาตรฐาน บ่อยครั้งที่มันจะเรียกว่าสิ่งที่ต้องการ (ในระบบที่มี Subtyping นี้อาจได้รับการจัดการโดยเพียงแค่มี⊥เป็นชนิดย่อยของทุกประเภท. แล้วแปลงเป็นนัย. อีกวิธีที่เกี่ยวข้องคือการกำหนด⊥เป็น∀ α . αซึ่งสามารถก็จะinstantiatedประเภทใด ๆ .)absurd
absurd
แน่นอนคุณต้องการที่จะมีฟังก์ชั่นดังกล่าวหรือเทียบเท่าเพราะมันเป็นสิ่งที่ช่วยให้คุณสามารถทำให้การใช้งานฟังก์ชั่นที่ผลิต⊥ตัวอย่างเช่นสมมติว่าฉันได้รับชนิดรวมฉันทำวิเคราะห์กรณีที่เกี่ยวกับมันและในกรณีที่ฉันกำลังจะไปโยนยกเว้นใช้ ⊥ ในกรณีที่ผมจะใช้F : → B โดยรวม, ฉันต้องการค่าของชนิดBดังนั้นฉันต้องการที่จะทำบางสิ่งบางอย่างที่จะเปิด⊥เป็นB นั่นคือสิ่งที่ฉันจะทำabsurd
ที่กล่าวว่ามีไม่มากทั้งเหตุผลที่จะกำหนดฟังก์ชั่นของตัวเองของabsurd
ตามคำนิยามที่พวกเขาจำเป็นต้องจะเป็นกรณีของ ถึงกระนั้นคุณอาจทำได้หากabsurd
ไม่มีไลบรารีมาตรฐานหรือคุณต้องการรุ่นเฉพาะประเภทเพื่อช่วยตรวจสอบ / อนุมานประเภท อย่างไรก็ตามคุณสามารถได้อย่างง่ายดายผลิตฟังก์ชั่นที่จะจบลงอินสแตนซ์ชนิดเช่น
ถึงแม้ว่าจะมีไม่มากเหตุผลที่จะเขียนฟังก์ชันดังกล่าวก็ควรโดยทั่วไปยังคงได้รับอนุญาต เหตุผลหนึ่งคือทำให้เครื่องมือ / มาโครการสร้างรหัสง่ายขึ้น
absurd
absurd
throw
เพื่อเพิ่มสิ่งที่ถูกกล่าวถึงเกี่ยวกับฟังก์ชั่นabsurd: ⊥ -> a
ฉันมีตัวอย่างที่ชัดเจนว่าฟังก์ชั่นนี้มีประโยชน์อย่างไร
พิจารณาประเภทข้อมูล Haskell Free f a
ซึ่งแสดงถึงโครงสร้างต้นไม้ทั่วไปที่มี f
โหนดรูปทรงและใบไม้ที่มีa
s:
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*
คาดไว้ ในทำนองเดียวกันประเภทของundefined
JavaScript ปลอดภัยในทางทฤษฎีจะต้องเป็นประเภทย่อยของทุกประเภทอื่น ๆ ในภาษา
exit()
throw()
Int
Int
exit()
NULL
ชนิดของหน่วยไม่ได้แตกต่างจาก⊥ซึ่งเป็นประเภทที่ว่างเปล่า?
void*
คุณจะต้องมีประเภทที่เฉพาะเจาะจงที่สามารถนำมาใช้สำหรับประเภทตัวชี้ใด ๆ
มีอยู่ครั้งหนึ่งที่ฉันนึกถึงและมันเป็นสิ่งที่ได้รับการพิจารณาว่าเป็นการพัฒนาภาษาโปรแกรม Swift
สวิฟท์มีmaybe
Monad สะกดหรือ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()))
?