Наберіть ролі та заплутану поведінку за допомогою "примусу"


11

У мене є тип, Id aі я намагаюся запобігти випадковому примусу, наприклад, Id Doubleдо ан Id 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щоб зробити це не так. Це питання задає питання, чому це не спрацювало.
Джозеф Сибл-

Відповіді:


12

Coercibleмає три можливі "типи" екземплярів (які автоматично генеруються компілятором, не визначені користувачем). Тільки на одну з них насправді впливають ролі .

  • Кожен тип примусовий до себе.
  • Ви можете примусити конструктор типу "під", за умови, що змінні типу є representationalабо phantom. Наприклад, ви можете примусити "a" Map Char Intдо того, Map Char (Data.Monoid.Sum Int)що для Mapнас є type role Map nominal representational.
  • Ви завжди можете примусити новий тип до базового типу і навпаки, за умови, що конструктор нового типу знаходиться в області застосування. Це ігнорує всі ролі! Обґрунтування полягає в тому, що, враховуючи, що конструктор доступний, ви завжди зможете загортати та розгортати його вручну, тому роль у будь-якому разі не дає вам ніякої безпеки.

У вашому прикладі застосовується третє правило. Якби новий тип був визначений в іншому модулі і конструктор не був імпортований, примус не зміг (щоб він знову працював, вам потрібно було б переключити роль phantom).

Дещо дивовижна особлива поведінка для нових типів пояснюється в цьому випуску GHC.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.