Ограничение строковых литералов только текстом
Я знаю, что OverloadedStrings
языковая прагма оборачивается неявным fromString
вокруг всех строковых литералов. То, что я хотел бы сделать, это на самом деле не перегружать строки, а просто изменить их значение, чтобы они всегда превращались в Text
и, следовательно, использование строкового литерала в качестве списка символов должно привести к ошибке типа.
Кажется, невозможно импортировать IsString
класс без импорта также String
экземпляр для этого класса. Предоставляет ли GHC какой-либо способ ограничить строковые литералы Text
только?
2 ответа
Это немного излишне, но одно решение состоит в том, чтобы объединить OverloadedStrings
а также RebindableSyntax
, RebindableSyntax
расширение вызывает все неявные вызовы функций, которые синтаксис Haskell использует для ссылки на любые функции в области видимости; например, целочисленные литералы используют любые fromIntegral
, не обязательно Prelude.fromIntegral
, Как побочный эффект, Prelude
больше не импортируется неявно, так что вы должны сделать это вручную. Пока вы импортируете его, не должно быть никаких проблем с синтаксисом, использующим неверную функцию неявно (я думаю - я фактически не использовал эту технику). В сочетании с OverloadedStrings
, это вызывает "foo"
быть преобразованным в fromString "foo"
за что fromString
по объему, не обязательно Data.String.fromString "foo"
, Итак, делая fromString
синоним pack
будет делать то, что вы хотите. Полный пример:
{-# LANGUAGE OverloadedStrings, RebindableSyntax #-}
import Prelude
import qualified Data.Text as T
import qualified Data.Text.IO as T
fromString :: String -> T.Text
fromString = T.pack
main :: IO ()
main = T.putStrLn "Hello, world!"
Это отлично работает, и меняется main
в main = putStrLn "Hello, world!"
выдает желаемую ошибку:
TestStrings.hs:11:17:
Couldn't match expected type `String' with actual type `T.Text'
Expected type: [Char] -> String
Actual type: String -> T.Text
In the first argument of `putStrLn', namely `"Hello, world!"'
In the expression: putStrLn "Hello, world!"
Комментируя определение fromString
вызывает другую ошибку:
TestStrings.hs:11:19:
Not in scope: `fromString'
Perhaps you meant `showString' (imported from Prelude)
Если вы хотите, чтобы он работал со строгим и ленивым текстом, вы можете определить свой собственный IsString
наберите class и создайте оба экземпляра; класс не должен называться IsString
просто пока у него есть fromString
метод.
Также предупреждаю: раздел руководства GHC по RebindableSyntax
не упоминает fromString
функция и раздел на OverloadedStrings
не упоминает RebindableSyntax
, Нет причин, по которым это не должно работать, но я думаю, это означает, что это решение технически основано на недокументированном поведении.
Не способ достичь этого сейчас, но, возможно, в конечном итоге, это instance force
как предложено в обсуждаемом предложении GHC, где вы бы сказали
instance force IsString Text
в вашем модуле. Это один из основных мотивирующих примеров для предложения.