พิมพ์บทบาทและพฤติกรรมที่ทำให้เกิดความสับสนโดย `coerce '


11

ฉันมีชนิดId aและฉันพยายามที่จะป้องกันไม่ให้ตั้งใจบีบบังคับเช่นการไปยังId DoubleId Int

หากฉันเข้าใจบทบาทพิมพ์อย่างถูกต้องสิ่งต่อไปนี้ไม่ควรรวบรวม

{-# LANGUAGE RoleAnnotations #-}
import Data.Coerce (coerce)

type role Id nominal
newtype Id a = Id String

badKey :: Id Int
badKey = coerce (Id "I point to a Double" :: Id Double)

น่าเสียดายที่มัน:

Prelude> :load Id.hs
[1 of 1] Compiling Main             ( Id.hs, interpreted )
Ok, one module loaded.
*Main> :type badKey
badKey :: Id Int

ฉันขาดอะไรเกี่ยวกับบทบาทประเภท


ain Idเป็นตัวแปรแฟนทอมและไม่มีผลกระทบกับมูลค่าที่แท้จริงภายใน หากคุณมีการnewtype Id a = Id aข่มขู่จะล้มเหลว
lehins

@ lehins จุดประสงค์ของการtype roleทำเช่นนั้นไม่ใช่กรณี คำถามนี้ถามว่าทำไมถึงไม่ได้ผล
Joseph Sible-Reinstate Monica

คำตอบ:


12

Coercibleมีอินสแตนซ์ "ประเภท" ที่เป็นไปได้สามแบบ (ซึ่งสร้างขึ้นโดยอัตโนมัติโดยคอมไพเลอร์ซึ่งไม่ได้กำหนดโดยผู้ใช้) เพียงหนึ่งของพวกเขาได้รับผลกระทบจริงโดยบทบาท

  • ทุกประเภทเป็นบีบบังคับกับตัวเอง
  • คุณสามารถบีบบังคับ "ภายใต้" ตัวสร้างประเภทให้ตัวแปรประเภทได้รับผลกระทบหรือrepresentational phantomตัวอย่างเช่นคุณสามารถบีบบังคับMap Char Intเป็นMap Char (Data.Monoid.Sum Int)เพราะเรามีMaptype role Map nominal representational
  • คุณสามารถเสมอบีบบังคับ Newtype ไปยังประเภทพื้นฐานและในทางกลับกันให้คอนสตรัค Newtype อยู่ในขอบเขต มันไม่สนใจบทบาททั้งหมด! เหตุผลก็คือเมื่อตัวสร้างพร้อมใช้งานคุณสามารถห่อและแกะด้วยตนเองได้ตลอดเวลาดังนั้นบทบาทนี้จึงไม่ได้ให้ความปลอดภัยใด ๆ แก่คุณ

ในตัวอย่างของคุณใช้กฎข้อที่สาม หากมีการกำหนดประเภทใหม่ในโมดูลอื่นและตัวสร้างไม่ได้นำเข้าการบีบบังคับจะล้มเหลว (เพื่อให้ทำงานได้อีกครั้งคุณจะต้องสลับบทบาทเป็นphantom)

ลักษณะการทำงานพิเศษที่ค่อนข้างน่าแปลกใจสำหรับ Newtypes มีการอธิบายในนี้ปัญหา GHC

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.