有点过度杀伤力,但一个解决方法是结合OverloadedStrings
和RebindableSyntax
。 RebindableSyntax
扩展会导致Haskell语法中的所有隐式函数调用引用当前作用域中的任何函数;例如,整数字面量使用任何fromIntegral
,而不一定是Prelude.fromIntegral
。副作用是Prelude
不再隐式导入,所以你必须手动导入它。只要你确实导入了它,使用错误的函数进行语法上的隐式转换就不应该有任何问题(我觉得—我实际上没有使用过这种技术)。当与OverloadedStrings
结合使用时,"foo"
会被转换为fromString "foo"
,其中fromString
是当前作用域中的任何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。虽然理论上来说这个解决方案应该是可行的,但我认为这意味着这个解决方案在技术上依赖于未记录的行为。
asText :: Text -> Text; asText = id
中并不是一个可接受的解决方案。 - Dan Burton