如何编写一个返回不同类型值的函数?

时间:2016-01-31 06:03:15

标签: haskell types

问题的标题是核心问题。这是为什么我需要这样的事情的背景。

我正在通过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

但是,我不相信这是最好的方法。还有其他方法吗?

4 个答案:

答案 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-idmessage-id,因为这只是内容的哈希值,这很可能是唯一的,因为它包含一个(唯一的)时间戳,只要您省略考虑因素的哈希冲突。

对于命令,我总是使用代数数据类型(ADT),因此我的服务器端逻辑被捕获在haskell中,我想限制执行" all"命令到手头的设置。

我不认为你想避免为此写作ADT,但也许认为这是太费力 - 这会让我回答你的问题并建议你也许写一些模板haskell为你生成你的ADT。

PS:我写这篇文章,知道你已经有两个很好的答案可以帮助你按照你要求的方向前进,但是想要给你一个不同的观点。

PPS:aeson具有自动派生fromJSONtoJSON个实例的强大功能 - 请参阅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"
  :}