Я хотел бы иметь возможность делать экземпляры IsString
с использованием расширения GHC OverloadedStrings
, так что мой экземпляр отклоняет некоторые литералы как недопустимые и такие, что это отклонение происходит во время компиляции, так что ошибки программирования не делают это в код, который я предоставляю своим пользователям.
У меня есть несколько вариантов использования, когда у меня есть тип Name
, который допускает только определенные строки. например.
module Name (Name(getName), makeName) where
import Data.Text (Text)
import qualified Data.Text as Text
-- | A guaranteed non-empty name.
newtype Name = Name { getName :: Text } deriving (Eq, Show, Ord)
makeName :: Text -> Maybe Name
makeName name
| Text.null name = Nothing
| otherwise = Just name
В реальном варианте использования я бы проверял правильные символы, а не начинал с цифры, что-то типа.
Идея состоит в том, что мы не экспортируем конструктор Name
, что означает, что любой, кто использует значение Name
, может доверять тому, что он имеет определенные свойства (в данном случае непустые).
Моя проблема в том, что я бы хотел использовать литералы во многих местах. например.
programName :: Name
programName = fromJust $ makeName "the-great-and-powerful-turtle"
Поскольку я делаю это много, я определил помощника unsafeMakeName
, который делает почти то же самое:
unsafeMakeName :: Text -> Name
unsafeMakeName name = fromMaybe (error $ "Invalid name: " <> Text.unpack name) (makeName name)
Проблема с этим подходом заключается в том, что, хотя причиной ошибки является ошибка программирования, я не узнаю об этом до времени выполнения.
Что бы я хотел сделать, это написать экземпляр IsString
для Name
, который выполняет эту проверку, например
instance IsString Name where
fromString = unsafeMakeName . Text.pack
... но чтобы получить ошибку о недопустимых именах в литералах во время компиляции.
Когда я пытаюсь это сделать, я только, кажется, получаю ошибки во время выполнения, когда используется буквальное значение. Это меньше, чем идеально, поскольку это ошибка в моем фактическом коде.
Есть ли способ сделать это? Это что-то, что можно было бы исправить в GHC? Заметьте, что я уже подал там ошибку.