【发布时间】:2015-05-29 18:13:54
【问题描述】:
我正在开发一个使用白色 Network.Wai 和 Network.Socket.Internal 模块的 Haskell 程序。在这个程序中,我有一个函数,定义如下:
prepareIp :: Request -> [([Char], [Char])]
prepareIp req = [("Remote", head $ splitOn ":" $ show $ remoteHost req)]
最初,我把它做成一个单子表达式(主要是为了可读性和清晰性),写成:
prepareIp :: Request -> [([Char], [Char])]
prepareIp req = do
ip <- head $ splitOn ":" $ show $ remoteHost req
[("Remote", ip)]
虽然前一个实现确实可以正常工作,但单子实现却抛出了一个我无法理解的错误:它的输出类型不是[([Char], [Char])],而是[([Char], Char)]——对于某些人来说,值ip是原因,变成了单个字符而不是字符串!
我还尝试在 GHCi 中对此进行原型设计,并使用模块引用以及 GHCi 中的 :t 进行类型检查,但无济于事,我仍然不知道是什么导致了这个错误。
谁能告诉我为什么会发生这种类型冲突?
【问题讨论】:
-
你为什么要返回一个列表,看起来你最好用
Request -> (String, String)(String只是[Char]的别名),然后就用@987654332 @,如果这对您来说还不够可读,那么请使用本地let,例如prepareIp req = let ip = head $ splitOn ":" $ show $ remoteHost req in ("Remote", ip),尽管为了便于阅读,混入了更多空格。 -
您也可能应该在
remoteHost req返回的SockAddr上进行模式匹配以提取IP(作为HostAddress或HostAddress6),而不是将其转换为要切片的字符串和骰子。 -
至于为什么它认为你需要
Char而不是[Char],这是因为当你拥有ip <-时,它会从<-右侧的列表中提取每个元素,并且由于在这种情况下head返回一个String,它等价于[Char],编译器期望ip具有Char类型。你真的只需要一个let,而不是单子。 -
@bheklilr 我不知道
Word32上的模式匹配是可能的(因为这就是HostAddress的全部内容——这怎么可能呢? -
您将在
SockAddr的构造函数上进行模式匹配,而不是在Word32本身:case remoteHost req of { SockAddrInet port addr -> ...; SockAddrInet6 port flow addr6 scope -> ...; SockAddrUnix addr -> ...}。
标签: haskell type-systems