我在他们的官方yesod书中关注Yesod教程。 (http://www.yesodweb.com/book/basics)
不幸的是,他们关于这本书的教程不会起作用,更糟糕的是它的输出是非常神秘的消息,关于不算数的类型让我花了很长时间才能理解。这是他们的原始代码和错误消息,由代码生成:
{-# 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
object
。我必须明确表达他们的类型:
import Data.Text (Text)
getHomeR = return $ object [("msg" :: Text) .= ("Hello World" :: Text)]
似乎Aeson
有Text
类型的JSON实例,我听说大部分文字处理代码都使用Text
类型,而不是String
([Char])出于效率原因。但是,如果每个双引号代码("msg"
,"Hello World"
)被自动解析为Text
而不是String
,那么它会不会很好?我认为OverloadedStrings
编译指示告诉编译器完全按照这样做("重载"将字符串转换为Text
),但是上面没有类型签名的错误表明我错了
当然,如果我必须为我为输出编写的每个字符串提供:: Text
类型签名,那将是非常繁琐和繁琐的 - 是否有任何解决方案,或者我只是不要理解足以编写Haskell和Yesod代码?
答案 0 :(得分:2)
使用OverloadedStrings时,显式字符串的处理方式与显式数字类似。所以
case DragEvent.ACTION_DROP:
final View droppedView = (View) event.getLocalState();
ViewGroup owner = (ViewGroup) droppedView.getParent();
owner.post(new Runnable(){
@Override
public void run() {
owner.removeView(droppedView);
}
});
}
被贬低为
x = "foo"
IsString类定义了“fromString”函数,所以现在所有类型检查器都知道
x = fromString "foo"
因此,这就是编译器抱怨类型不明确的原因。有几种不同的字符串类型与ToJSON实例,编译器抱怨它不知道选择哪一个。
我担心的唯一解决方案是丢失OverloadedStrings或输入显式类型注释以告诉编译器选择哪个实例。
On String vs. Text:当你使用像这样的短常量字符串时,效率不是一个特别大的问题。如果你正在批量处理文本,那么它是一个更大的问题,而且在某些语言中,String = [Char]的Haskell概念也会崩溃。文本正确处理这些,但String不能。因此,如果您需要将代码国际化,那么当您尝试执行诸如大写单词之类的操作时,String会向您显示模糊的问题。
答案 1 :(得分:2)
您正在查看的JSON代码段确实可以直接在本书中正常工作。在它的顶部还有一个额外的pragma,你的代码中缺少这个pragma:
getHomeR = return $ object ["msg" .= ("Hello World" :: String)]
我并不是代码片段的忠实粉丝,因为我非常确定人们不会在生产代码中使用该pragma。编写像这样的代码更典型:
ExtendedDefaultRules
请注意,GHCi使用object ["msg" .= "Hello World"]
可以更轻松地将表达式输入REPL,而无需指定其类型。如果您在GHCi中输入ghci > object ["msg" .= "Hello World"]
<interactive>:2:18: Warning:
Defaulting the following constraint(s) to type ‘String’
(IsString a0)
arising from the literal ‘"Hello World"’ at <interactive>:2:18-30
(ToJSON a0) arising from a use of ‘.=’ at <interactive>:2:15-16
In the second argument of ‘(.=)’, namely ‘"Hello World"’
In the expression: "msg" .= "Hello World"
In the first argument of ‘object’, namely
‘["msg" .= "Hello World"]’
<interactive>:2:18: Warning:
Defaulting the following constraint(s) to type ‘String’
(IsString a0)
arising from the literal ‘"Hello World"’ at <interactive>:2:18-30
(ToJSON a0) arising from a use of ‘.=’ at <interactive>:2:15-16
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 (fromList [("msg",String "Hello World")])
,它会告诉您它的默认值是什么:
Class CommunicationThread extends Thread {
//Vector containing all client sockets currently connected
//Held offsite, here for clarity
public Vector<Socket> socketVector;
public CommunicationThread (Socket clientSoc, Server ec3, Vector<Socket>socketVectorg)
{
//add new socket to vector, start thread
clientSocket = clientSoc;
socketVectorg.add(clientSocket);
this.socketVector = socketVectorg;
gui = ec3;
}
public void run()
{
System.out.println ("New Communication Thread Started");
try {
//Client's chat box (output)
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),
true);
//Input line from client
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println("Server: " + inputLine);
gui.history.insert(inputLine + "\n", 0);
//*************HERE IS MY ISSUE*******************
for(Socket s : socketVector){
out = new PrintWriter(s.getOutputStream(),
true);
out.println(inputLine);
}
if (inputLine.equals("Bye."))
break;
if (inputLine.equals("End Server."))
gui.serverContinue = false;
}
out.close();
in.close();
clientSocket.close();
}
catch (IOException e)
{
System.err.println("Problem with Communication Server");
//System.exit(1);
}
}
}
答案 2 :(得分:1)
object
将Pair
值列表作为参数。 Pair
是type Pair = (Text, Value)
,它是tye KeyValue
类型类的实例,它提供了方便构造函数(.=) :: ToJSON v => Text -> v -> kv
。
问题如下:.=
要求值类型具有ToJSON
实例,但不会强制调用者进入任何具体类型。
同时,来自IsString
的{{3}}函数在其返回类型上重载:fromString :: String -> a
。调用的精确实现由返回类型确定。使用OverloadedStrings
时,会为字符串文字隐式调用fromString
。
如果我们直接将fromString
的结果作为.=
的值参数提供,则编译器没有足够的信息来为该值指定具体类型。它应该创建Text
值并将其转换为json吗?或者也许创建一个ByteString
并将其转换为json?问题类似于show . read
等含糊不清的作品。
就个人而言,我不是使用类型注释,而是使用Value
类型的fromString
构造函数包装字符串文字来解决歧义。它告诉编译器文字将是Text
,当然Value
是ToJSON
的实例。这比类型注释要简洁一些:
foo :: Value
foo = object ["foo" .= String "faa"]
您还可以定义.=
的特化,其中以Text
为具体值:
(.=|) :: KeyValue kv => Text -> Text -> kv
(.=|) = (.=)
foo :: Value
foo = object ["foo" .=| "faa"]