“-XOverloadedStrings”是如何工作的?(用Yesod表示)

“-XOverloadedStrings”是如何工作的?(用Yesod表示),string,haskell,text,yesod,String,Haskell,Text,Yesod,我正在关注他们官方的Yesod书中的Yesod教程。() 不幸的是,他们关于这本书的教程不起作用,更糟糕的是,它的输出是关于类型不匹配的非常隐晦的信息,我花了很长时间才理解。这是他们的原始代码和由代码生成的错误消息: {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilie

我正在关注他们官方的Yesod书中的Yesod教程。()

不幸的是,他们关于这本书的教程不起作用,更糟糕的是,它的输出是关于类型不匹配的非常隐晦的信息,我花了很长时间才理解。这是他们的原始代码和由代码生成的错误消息:

{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE QuasiQuotes           #-}
{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE TypeFamilies          #-}
import           Yesod

data Links = Links

mkYesod "Links" [parseRoutes|
/ HomeR GET
|]

instance Yesod Links

getHomeR = return $ object ["msg" .= "Hello World"]

main :: IO ()
main = warp 3000 Links
错误:

helloworld2.hs:18:36:
    No instance for (ToJSON a0) arising from a use of ‘.=’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance ToJSON a => ToJSON (Control.Applicative.Const a b)
        -- Defined in ‘Data.Aeson.Compat’
      instance ToJSON (Data.Proxy.Proxy a)
        -- Defined in ‘Data.Aeson.Compat’
      instance ToJSON Data.Version.Version
        -- Defined in ‘Data.Aeson.Compat’
      ...plus 7 others
    In the expression: "msg" .= "Hello World"
    In the first argument of ‘object’, namely
      ‘["msg" .= "Hello World"]’
    In the second argument of ‘($)’, namely
      ‘object ["msg" .= "Hello World"]’

helloworld2.hs:18:40:
    No instance for (Data.String.IsString a0)
      arising from the literal ‘"Hello World"’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Data.String.IsString Value
        -- Defined in ‘aeson-0.9.0.1:Data.Aeson.Types.Internal’
      instance (a ~ Data.ByteString.Internal.ByteString) =>
               Data.String.IsString
                 (attoparsec-0.13.0.1:Data.Attoparsec.ByteString.Internal.Parser a)
        -- Defined in ‘Data.Attoparsec.ByteString.Char8’
      instance (a ~ Data.Text.Internal.Text) =>
               Data.String.IsString
                 (attoparsec-0.13.0.1:Data.Attoparsec.Text.Internal.Parser a)
        -- Defined in ‘attoparsec-0.13.0.1:Data.Attoparsec.Text.Internal’
      ...plus 9 others
    In the second argument of ‘(.=)’, namely ‘"Hello World"’
    In the expression: "msg" .= "Hello World"
    In the first argument of ‘object’, namely
      ‘["msg" .= "Hello World"]’
问题似乎出在
object[“msg”=“Hello World”]
上。GHC不了解什么类型的
“msg”
“Hello World”
,也不能用它们构建
JSON
对象。我必须明确他们的类型,即:

import           Data.Text (Text)
getHomeR = return $ object [("msg" :: Text) .= ("Hello World" :: Text)]
似乎
Aeson
必须为
Text
类型使用JSON实例,而且我听说大多数文本处理代码出于效率原因使用
Text
类型,而不是
String
([Char])。但是如果每个双引号代码(
“msg”
“Hello World”
)被自动解析为
文本而不是
字符串,那不是很好吗?我认为
OverloadedStrings
pragma会告诉编译器完全这样做(“重载”字符串到
Text
),但是上面没有类型签名的错误表明我错了


当然,如果我必须为我为输出而编写的每个字符串提供
::Text
类型签名,这将是非常乏味和麻烦的-有什么解决方案吗,或者是我对编写Haskell和Yesod代码理解不够?

当使用重载字符串时,显式字符串的处理方式与显式数字类似。所以

x = "foo"
脱去糖衣

x = fromString "foo"
IsString类定义了“fromString”函数,因此类型检查器现在只知道

x :: (IsString a) => a
这就是编译器抱怨类型不明确的原因。ToJSON实例有几种不同的字符串类型,编译器抱怨它不知道选择哪一种

我担心,唯一的解决方案是丢失重载字符串,或者放入显式类型注释来告诉编译器选择哪个实例


关于字符串与文本:当您使用这样的短常量字符串时,效率不是一个特别大的问题。如果您正在批量处理文本,那么这是一个更大的问题,而且在某些语言中,Haskell的String=[Char]概念也会崩溃。文本可以正确地处理这些,但字符串不能。所以,如果您需要对代码进行国际化,那么当您尝试将单词大写时,字符串可能会给您带来一些模糊的问题。

当您使用重载字符串时,显式字符串的处理方式与显式数字类似。所以

x = "foo"
脱去糖衣

x = fromString "foo"
IsString类定义了“fromString”函数,因此类型检查器现在只知道

x :: (IsString a) => a
这就是编译器抱怨类型不明确的原因。ToJSON实例有几种不同的字符串类型,编译器抱怨它不知道选择哪一种

我担心,唯一的解决方案是丢失重载字符串,或者放入显式类型注释来告诉编译器选择哪个实例


关于字符串与文本:当您使用这样的短常量字符串时,效率不是一个特别大的问题。如果您正在批量处理文本,那么这是一个更大的问题,而且在某些语言中,Haskell的String=[Char]概念也会崩溃。文本可以正确地处理这些,但字符串不能。所以,如果您需要对代码进行国际化,那么当您尝试使用大写字母之类的操作时,字符串可能会给您带来一些模糊的问题。

对象
将一组
值作为参数
Pair
type Pair=(Text,Value)
,是tye
KeyValue
typeclass的一个实例,它提供了方便的构造函数
(..=)::ToJSON v=>Text->v->kv

问题如下:
=
要求值类型具有
ToJSON
实例,但不强制调用方使用任何具体类型

同时,
IsString
中的函数在其返回类型上重载:
fromString::String->a
。要调用的精确实现由返回类型决定。当使用
OverloadedStrings
时,将为字符串文本隐式调用
fromString

如果我们直接将
fromString
的结果作为
=
的值参数提供,编译器没有足够的信息将具体类型分配给值。它应该创建一个
Text
值并将其转换为json吗?或者创建一个
ByteString
,并将其转换为json?这个问题类似于模棱两可的组合,比如
show。阅读

就个人而言,我不使用类型注释,而是使用
值的构造函数
类型来包装字符串文本,从而解决歧义。它告诉编译器文本将是
Text
,当然
Value
ToJSON
的一个实例。这比类型注释要简单一些:

foo :: Value
foo = object ["foo" .= String "faa"]
您还可以定义一个专门化的
=
,将具体的
文本作为值:

(.=|) :: KeyValue kv => Text -> Text -> kv 
(.=|) = (.=)

foo :: Value
foo = object ["foo" .=| "faa"] 

对象
值的列表作为参数
Pair
type Pair=(Text,Value)
,是tye
KeyValue
typeclass的一个实例,它提供了方便的构造函数
(..=)::ToJSON v=>Text->v->kv

问题如下:
=
要求值类型具有
ToJSON
实例,但不强制调用方使用任何具体类型

同时,
IsString
中的函数在其返回类型上重载:
fromString::String->a
。要调用的精确实现由re确定