Ограничение строковых литералов только текстом

Я знаю, что 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

в вашем модуле. Это один из основных мотивирующих примеров для предложения.

Другие вопросы по тегам