haskell - Restringir literales de cadena a solo texto
ghc string-literals (2)
Soy consciente de que el lenguaje pragma OverloadedStrings
envuelve implícita fromString
alrededor de todos los literales de cadena. Lo que me gustaría hacer es no sobrecargar las cadenas, sino simplemente cambiar su significado para que siempre se conviertan en Text
, y por lo tanto, usar un literal de cadena como una lista de caracteres debería resultar en un error de tipo.
Parece imposible importar la clase IsString
sin importar también la instancia de String
para esa clase. ¿Ghc me proporciona alguna forma de restringir los literales de cadena a solo Text
?
Es un poco exagerado, pero una solución es combinar OverloadedStrings
y RebindableSyntax
. La extensión RebindableSyntax
causa que todas las llamadas a funciones implícitas que usa la sintaxis Haskell se refieran a cualquier función que esté dentro del alcance; por ejemplo, los literales enteros usan cualquiera de fromIntegral
, no necesariamente Prelude.fromIntegral
. Como efecto secundario, Prelude
ya no se importa implícitamente, por lo que debe hacerlo manualmente. Mientras lo importe, no debería haber ningún problema con la sintaxis que use la función incorrecta implícitamente (creo que no he usado esta técnica). Cuando se combina con OverloadedStrings
, esto hace que "foo"
se transforme en fromString "foo"
para el fromString
cualquier fromString
, no necesariamente Data.String.fromString "foo"
. Así que hacer fromString
con el pack
hará lo que quieras. Un ejemplo completo:
{-# 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!"
Esto funciona bien, y cambiando main
a main = putStrLn "Hello, world!"
produce el error deseado:
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!"
Comentando la definición de fromString
causa un error diferente:
TestStrings.hs:11:19:
Not in scope: `fromString''
Perhaps you meant `showString'' (imported from Prelude)
Si desea que funcione con texto estricto y perezoso, puede definir su propia clase de tipo IsString
y convertir ambas instancias; la clase no tiene que llamarse IsString
, siempre que tenga un método fromString
.
Además, una palabra de advertencia: la sección del manual de GHC sobre RebindableSyntax
no menciona la función fromString
, y la sección sobre OverloadedStrings
no menciona RebindableSyntax
. No hay razón para que esto no funcione, pero creo que eso significa que esta solución se basa técnicamente en un comportamiento no documentado.
No es una forma de lograr esto ahora, pero tal vez con el tiempo, es la instance force
como se propone en una propuesta de característica GHC en discusión , donde diría
instance force IsString Text
en tu módulo Este es uno de los principales ejemplos de motivación para la propuesta.