มีกรณีการใช้งานสำหรับประเภทด้านล่างเป็นประเภทพารามิเตอร์ฟังก์ชั่น?


12

หากฟังก์ชันมีชนิดส่งคืนเป็น⊥ ( ชนิดด้านล่าง ) นั่นหมายความว่าจะไม่ส่งคืน มันสามารถยกตัวอย่างเช่นออกหรือโยนทั้งสถานการณ์ธรรมดา

สันนิษฐานว่าถ้าฟังก์ชั่นมีพารามิเตอร์ประเภท⊥มันจะไม่สามารถเรียก (ปลอดภัย) มีเหตุผลใดบ้างในการนิยามฟังก์ชั่นดังกล่าว?

คำตอบ:


17

หนึ่งในการกำหนดคุณสมบัติของหรือประเภทที่ว่างเปล่าว่ามีฟังก์ชั่นAทุกประเภท ในความเป็นจริงมีฟังก์ชั่นดังกล่าวที่ไม่ซ้ำกันอยู่ ดังนั้นจึงเหมาะสมสำหรับฟังก์ชั่นนี้ในการเป็นส่วนหนึ่งของไลบรารีมาตรฐาน บ่อยครั้งที่มันจะเรียกว่าสิ่งที่ต้องการ (ในระบบที่มี Subtyping นี้อาจได้รับการจัดการโดยเพียงแค่มีเป็นชนิดย่อยของทุกประเภท. แล้วแปลงเป็นนัย. อีกวิธีที่เกี่ยวข้องคือการกำหนดเป็นα . αซึ่งสามารถก็จะinstantiatedประเภทใด ๆ .)Aabsurdabsurd α.α

แน่นอนคุณต้องการที่จะมีฟังก์ชั่นดังกล่าวหรือเทียบเท่าเพราะมันเป็นสิ่งที่ช่วยให้คุณสามารถทำให้การใช้งานฟังก์ชั่นที่ผลิต⊥ตัวอย่างเช่นสมมติว่าฉันได้รับชนิดรวมE+Aฉันทำวิเคราะห์กรณีที่เกี่ยวกับมันและในEกรณีที่ฉันกำลังจะไปโยนยกเว้นใช้throw:E ในกรณีที่ผมจะใช้F : B โดยรวม, ฉันต้องการค่าของชนิดBดังนั้นฉันต้องการที่จะทำบางสิ่งบางอย่างที่จะเปิดเป็นB นั่นคือสิ่งที่ฉันจะทำAf:ABBBabsurd

ที่กล่าวว่ามีไม่มากทั้งเหตุผลที่จะกำหนดฟังก์ชั่นของตัวเองของAabsurdตามคำนิยามที่พวกเขาจำเป็นต้องจะเป็นกรณีของ ถึงกระนั้นคุณอาจทำได้หากabsurdไม่มีไลบรารีมาตรฐานหรือคุณต้องการรุ่นเฉพาะประเภทเพื่อช่วยตรวจสอบ / อนุมานประเภท อย่างไรก็ตามคุณสามารถได้อย่างง่ายดายผลิตฟังก์ชั่นที่จะจบลงอินสแตนซ์ชนิดเช่นA

ถึงแม้ว่าจะมีไม่มากเหตุผลที่จะเขียนฟังก์ชันดังกล่าวก็ควรโดยทั่วไปยังคงได้รับอนุญาต เหตุผลหนึ่งคือทำให้เครื่องมือ / มาโครการสร้างรหัสง่ายขึ้น


ดังนั้นนี่หมายถึงบางสิ่งบางอย่างที่(x ? 3 : throw new Exception())ได้รับการแทนที่เพื่อการวิเคราะห์ด้วยบางสิ่งที่มากกว่า(x ? 3 : absurd(throw new Exception()))?
bdsl

หากคุณไม่ได้มี Subtyping หรือไม่ได้กำหนดเป็นอัลฟ่า α , จากนั้นอดีตจะไม่พิมพ์เช็คและหลังจะ ด้วยการพิมพ์ย่อยใช่สิ่งที่ชอบจะถูกแทรกโดยปริยาย แน่นอนคุณสามารถใส่ภายในนิยามของซึ่งเป็นสิ่งที่มีประสิทธิภาพการกำหนดเป็นอัลฟ่า αน่าจะทำ α.αabsurdabsurdthrowα.α
ดีเร็กเอลกินส์ซ้าย SE

6

เพื่อเพิ่มสิ่งที่ถูกกล่าวถึงเกี่ยวกับฟังก์ชั่น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แสดงให้เห็นว่า!


2

ประเภทด้านล่างเป็นประเภทย่อยของประเภทอื่น ๆ ทุกประเภทซึ่งอาจเป็นประโยชน์อย่างมากในทางปฏิบัติ ตัวอย่างเช่นประเภทของNULLรุ่นที่ปลอดภัยในเชิงทฤษฎีของ C จะต้องเป็นประเภทย่อยของตัวชี้ประเภทอื่น ๆ ทุกประเภทไม่เช่นนั้นคุณจะไม่สามารถกลับไปNULLที่ตำแหน่งที่char*คาดไว้ ในทำนองเดียวกันประเภทของundefinedJavaScript ปลอดภัยในทางทฤษฎีจะต้องเป็นประเภทย่อยของทุกประเภทอื่น ๆ ในภาษา

exit()throw()IntIntexit()

TST


3
NULLชนิดของหน่วยไม่ได้แตกต่างจาก⊥ซึ่งเป็นประเภทที่ว่างเปล่า?
bdsl

ฉันไม่แน่ใจในความหมายของทฤษฎีประเภท.
bdsl

1
@bdsl ตัวดำเนินการโค้งที่นี่คือ "เป็นประเภทย่อย"; ฉันไม่แน่ใจว่ามันเป็นมาตรฐานหรือเปล่าเป็นสิ่งที่อาจารย์ใช้
Draconis

1
@ gnasher729 จริง แต่ C ก็ไม่ได้เป็นประเภทที่ปลอดภัยโดยเฉพาะ ฉันกำลังบอกว่าถ้าคุณไม่เพียงแค่โยนจำนวนเต็มvoid*คุณจะต้องมีประเภทที่เฉพาะเจาะจงที่สามารถนำมาใช้สำหรับประเภทตัวชี้ใด ๆ
Draconis


2

มีอยู่ครั้งหนึ่งที่ฉันนึกถึงและมันเป็นสิ่งที่ได้รับการพิจารณาว่าเป็นการพัฒนาภาษาโปรแกรม 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??


0

Swift มีประเภท "ไม่เคย" ซึ่งดูเหมือนว่าจะเป็นประเภทล่าง: ฟังก์ชั่นที่ประกาศให้คืนไม่สามารถย้อนกลับได้ฟังก์ชันที่ใช้พารามิเตอร์ประเภทไม่สามารถเรียกได้

สิ่งนี้มีประโยชน์ในการเชื่อมต่อกับโปรโตคอลซึ่งอาจมีข้อ จำกัด เนื่องจากระบบประเภทของภาษาที่คลาสจะต้องมีฟังก์ชั่นบางอย่าง แต่ไม่มีความต้องการที่จะเรียกใช้ฟังก์ชั่นนี้และไม่ต้องการสิ่งที่ประเภทอาร์กิวเมนต์ อยากจะเป็น.

สำหรับรายละเอียดคุณควรดูที่โพสต์ที่ใหม่กว่าในรายชื่อผู้รับจดหมายอย่างรวดเร็ว


7
"โพสต์ที่ใหม่กว่าในรายชื่อผู้รับจดหมายของ swift-evolution" ไม่ใช่การอ้างอิงที่ชัดเจนหรือมีเสถียรภาพ ไม่มีเว็บเก็บถาวรของรายการส่งเมลหรือไม่
Derek Elkins ออกจาก SE
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.