问题的标题是核心问题。这是为什么我需要这样的事情的背景。
我正在通过Websocket处理JSON-RPC接口。这意味着请求 - 响应周期是完全异步的。当我发出一个请求时,我给它一个唯一的ID,异步响应包含该ID(以帮助将请求 - 响应结合在一起)。
现在,我需要使用Aeson将响应JSON解析为Haskell对象。无论我采用哪种方式构建它,我都需要在我的代码中的某个位置使用具有以下类型签名的函数:
0 * * * * export DISPLAY=:0 && vlc /home/user/video_name.mp4
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
rpcId2HaskellType :: String -> a
并非每种类型都在阳光下,而是一组我所期待的一些已知类型。
我能想到的一个解决方案是创建一个代数数据类型并将其用作a
的返回类型
rpcId2HaskellType
但是,我不相信这是最好的方法。还有其他方法吗?
答案 0 :(得分:3)
我相信您正在寻找的是aeson中的FromJSON类型类。
所以在你的情况下:rpcId2HaskellType :: FromJSON a => String -> a
但是我愿意打赌rpcId
在你的协议中有一致的类型,所以它应该取决于你的输入函数来进行转换。
答案 1 :(得分:1)
有两种情况。如果您知道在rpcId2HaskellType
的任何特定用途中您期望的类型,则可以使用与Read
类型类完全相同的类型类。
另一种情况是,如果您需要分析结果以了解您拥有的类型,然后根据具体情况执行不同的逻辑。在这种情况下,代数数据类型可能是表示它的最佳方式。
对于后一种情况,使用存在性数据类型还有另一种方法,但它几乎总是一个坏主意。它背后的想法并不太可怕(并且在OO编程中很常见),它具有返回值" know"如何做你想做的任何事情本身。然后你的代码就会要求它做那件事。但是,在FP中,通常情况下数据会变得愚蠢。
答案 2 :(得分:1)
我只是在猜测,因为我没有足够的信息来证明这一点,但我认为你没有提出正确的问题。
我假设您的JSON-RPC看起来像这样:
request.json
{ message-id: "asec-ureh-asho-fcon-tent"
, content: { timestamp: "2016-01-31T10:23:10.123456"
, command: { name: "mycommand"
, parameters: [..]
}
}
}
response.json
{ message-id: "asec-ureh-asho-fthi-scon-tent"
, content: { timestamp: "2016-01-31T10:26:10.123456"
, result: {..}
, original-id: "asec-ureh-asho-fcon-tent"
}
}
然后我不明白为什么你需要转换rpc-id
或message-id
,因为这只是内容的哈希值,这很可能是唯一的,因为它包含一个(唯一的)时间戳,只要您省略考虑因素的哈希冲突。
对于命令,我总是使用代数数据类型(ADT),因此我的服务器端逻辑被捕获在haskell中,我想限制执行" all"命令到手头的设置。
我不认为你想避免为此写作ADT,但也许认为这是太费力 - 这会让我回答你的问题并建议你也许写一些模板haskell为你生成你的ADT。
PS:我写这篇文章,知道你已经有两个很好的答案可以帮助你按照你要求的方向前进,但是想要给你一个不同的观点。 PPS:aeson
具有自动派生fromJSON
和toJSON
个实例的强大功能 - 请参阅package description。
答案 3 :(得分:0)
在Haskell中,无法编写返回不同类型值的函数。原因是Haskell是静态类型的。
此操作失败:
:{
g 1 = 2
g 2 = "3"
:}
但是您可以创建自己的ADT类型。
这有效:
data IntString = IString String | IntS Int deriving Show
:{
g :: Int -> IntString
g 1 = IntS 2
g 2 = IString "3"
:}