Использование перегруженных строк

OverloadedStrings расширение действительно очень полезно, однако оно имеет некоторые недостатки. Рассмотрим следующее определение функции:

someFunction :: ToJSSTring a => a -> IO ()
someFunction = js_function . toJSSTring

В этом случае, если я хочу передать литеральное значение, я должен явно добавить подпись типа, когда включен OverloadedStrings:

someFunction ("This is plain string" :: String)
someFunction ("And this one is Text" :: Data.Text.Text)

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

Вопрос в том, есть ли способ, скажем, по умолчанию все строковые литералы без подписи типов к Text или String? Или я должен просто разделить мой код на общие функции (с ограничением типа ToJSString) и произвольными, которые имеют строгие сигнатуры типов для своих аргументов?

Ответ 1

Вы можете включить ExtendedDefaultRules (https://www.fpcomplete.com/user/snoyberg/random-code-snippets/overloadedstrings-defaults):

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ExtendedDefaultRules #-}
import Data.Text (Text, pack)

newtype JSString = JSString Text
    deriving Show

class ToJSString a where
    toJSString :: a -> JSString
instance ToJSString [Char] where
    toJSString = toJSString . pack
instance ToJSString Text where
    toJSString = JSString

someFunction :: ToJSString a => a -> IO ()
someFunction = print . toJSString

main :: IO ()
main = someFunction "Hello World"

EDIT. Вы также можете добавить default (Text) в начало своего модуля, чтобы по умолчанию использовать Text вместо String.