【问题标题】:How write a function that returns values of different types?如何编写一个返回不同类型值的函数?
【发布时间】:2020-07-02 02:50:31
【问题描述】:

问题的标题提出了核心问题。这是为什么我需要这样的东西的背景。

我正在通过 Websocket 处理 JSON-RPC 接口。这意味着请求-响应周期是完全异步的。当我发出一个请求时,我给它一个唯一的 ID,异步响应包含该 ID(以帮助将请求-响应联系在一起)。

现在,我需要使用 Aeson 将响应 JSON 解析为 Haskell 对象。无论我采用哪种方式构建它,我都需要在代码中的某个位置具有以下类型签名的函数:

rpcId2HaskellType :: String -> a

a 并不是所有的类型,而是一组我期望响应的少数已知类型。

我能想到的一个解决方案是创建一个代数数据类型并将其用作rpcId2HaskellType 的返回类型

data UnnecessaryAlgebraicDataType = ResponseType1 | ResponseType1 | ResponseType3
rpcId2HaskellType :: String -> UnnecessaryAlgebraicDataType

但是,我不相信这是最好的方法。有没有其他方法可以做到这一点?

【问题讨论】:

    标签: haskell types


    【解决方案1】:

    我相信您正在寻找的是 aeson 中的 FromJSON 类型类。

    所以在你的情况下:rpcId2HaskellType :: FromJSON a => String -> a

    但我敢打赌,rpcId 在您的协议中具有一致的类型,因此应该由您的输入函数来进行转换。

    【讨论】:

      【解决方案2】:

      有两种情况。如果您知道在 rpcId2HaskellType 的任何特定用途中所期望的类型,您可以使用与 Read 类型类完全相同的类型类。

      另一种情况是,如果您需要分析结果以了解您拥有的类型,然后根据该类型执行不同的逻辑。在这种情况下,代数数据类型可能是表示它的最佳方式。

      对于后一种情况,还有另一种使用存在数据类型的方法,但这几乎总是一个坏主意。它背后的想法并不太糟糕(并且在 OO 编程中很常见),即让返回值“知道”如何用它本身做任何你想做的事情。然后你的代码就变成了要求它做那件事。不过,在 FP 中,数据通常最好是哑巴的。

      【讨论】:

        【解决方案3】:

        我只是猜测,因为我没有足够的信息来证明这一点,但我认为你问的问题不正确。

        我假设你的 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 中捕获,并且我想将“所有”命令的执行限制在手头的集合中。

        我不认为你想避免为此编写 ADT,但可能认为这太费力了 - 这会导致我回避你的问题并建议你编写一些模板 haskell 来生成你的 ADT给你。

        PS.:我写这篇文章,知道你已经得到了两个很好的答案,可以帮助你朝着你所要求的方向前进,但想给你一个不同的观点。

        PPS.:aeson 具有自动派生 fromJSONtoJSON 实例的强大功能 - 请参阅 package description 了解相关信息。

        【讨论】:

          【解决方案4】:

          在 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"
            :}
          
          

          【讨论】:

            猜你喜欢
            • 2020-11-04
            • 1970-01-01
            • 1970-01-01
            • 2020-04-02
            • 1970-01-01
            • 2016-07-07
            • 1970-01-01
            • 2011-06-24
            • 1970-01-01
            相关资源
            最近更新 更多