Подтвердить что ты не робот

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

Я знаю, что языковая прагма OverloadedStrings обертывает неявный fromString вокруг всех строковых литералов. То, что я хотел бы сделать, на самом деле не перегружает строки, а просто изменяет их значение, так что они всегда превращаются в Text, и поэтому использование строкового литерала в виде списка символов должно приводить к ошибке типа.

Кажется, невозможно импортировать класс IsString, не импортируя экземпляр String для этого класса. Предоставляет ли ghc какой-то способ ограничить строковые литералы только Text?

4b9b3361

Ответ 1

Это немного перебор, но одно решение состоит в объединении 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 и сделать оба экземпляра; класс не должен называться IsString, только если он имеет метод fromString.

Кроме того, слово предупреждения: в разделе руководства GHC на RebindableSyntax не упоминается функция fromString, а в разделе OverloadedStrings не упоминается RebindableSyntax. Нет причин, по которым это не должно работать, но я думаю, это означает, что это решение технически зависит от недокументированного поведения.

Ответ 2

Невозможно достичь этого сейчас, но, возможно, в конце концов, это instance force, как предлагается в