我在Haskell中遇到协议缓冲区问题。我正在写一个简单的UDP接收器并得到错误:
src/Main.hs:39:25:
Ambiguous type variable `msg0' in the constraints:
(Wire msg0)
arising from a use of `messageGet' at src/Main.hs:39:25-34
(Text.ProtocolBuffers.Reflections.ReflectDescriptor msg0)
arising from a use of `messageGet' at src/Main.hs:39:25-34
Probable fix: add a type signature that fixes these type variable(s)
In the expression: (messageGet (B.pack mesg))
In the second argument of `($)', namely
`case (messageGet (B.pack mesg)) of {
Left person -> putStrLn $ show person
Right err -> error $ "Failed to parse address book." }'
In a stmt of a 'do' block:
return
$ case (messageGet (B.pack mesg)) of {
Left person -> putStrLn $ show person
Right err -> error $ "Failed to parse address book." }
我如何遵循它的建议? (我刚刚学习Haskell。)
我的守则如下:
module Main where
import Data.Bits
import Network.Socket -- hiding (send, sendTo, recv, recvFrom)
-- import Network.Socket.ByteString
import Network.BSD
import Data.List
import qualified Data.ByteString.Lazy.Char8 as B
import Text.ProtocolBuffers.Header (defaultValue, uFromString)
import Text.ProtocolBuffers.WireMessage (messageGet, messagePut, Wire)
import Data.Sequence ((><), fromList)
import AddressBookProtos.AddressBook
import AddressBookProtos.Person
import AddressBookProtos.Person.PhoneNumber
import AddressBookProtos.Person.PhoneType
import Network.Socket
import System.Posix.Directory
import System.Posix.Files
import System.Posix.IO
import System.Posix.Process
import System.Exit
echoserver :: IO ()
echoserver = do
withSocketsDo $ do
sock <- socket AF_INET Datagram 0
bindSocket sock (SockAddrInet 4567 iNADDR_ANY)
socketRx sock
socketRx :: Socket -> IO ()
socketRx sock = do
(mesg, recv_count, client) <- recvFrom sock 1500
return $ case (messageGet (B.pack mesg)) of
Left person -> putStrLn $ show person
Right err -> error $ "Failed to parse address book."
socketRx sock
main::IO()
main = echoserver
答案 0 :(得分:3)
在http://hackage.haskell.org/packages/archive/protocol-buffers/2.0.9/doc/html/Text-ProtocolBuffers-WireMessage.html#v:messageGet的文档中,messageGet
的类型签名是
messageGet :: (ReflectDescriptor msg, Wire msg) => ByteString -> Either String (msg, ByteString)
返回值是String
错误消息或msg
和剩余ByteString
。在你的代码中,你写了
case messageGet (B.pack mesg) of
Left person -> putStrLn $ show person
Right err -> error "Failed to parse address book."
如果返回(msg, ByteString)
,则该值绑定到变量err
。由于err
被忽略,因此未确定msg
的实际类型,这是错误消息告诉您的内容。实际上,任何类型都是Wire
和ReflectDescriptor
的实例,但程序对每种类型的行为都不同!由于编译器不知道您想要的类型,因此您必须指定它。您可以通过注释messageGet
的返回类型来指定它。
case messageGet (B.pack mesg) :: Either String (X, ByteString) of -- Use the actual message type in place of 'X'
Left person -> putStrLn $ show person
Right err -> error "Failed to parse address book."
您可能还想在代码中切换Left
和Right
个案例。 Right
是非错误情况(认为“错误”和“正确”)。切换案例不会自行消除错误信息。
答案 1 :(得分:1)
添加类似的类型注释:
return $ case messageGet (B.pack mesg) :: Either Something SomethingElse of
(我不熟悉协议缓冲区,所以我不知道Something
和SomethingElse
应该是什么类型---用你需要的实际类型替换它们。)