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

Haskell 如何编写返回不同类型值的函数?,haskell,types,Haskell,Types,问题的标题提出了核心问题。这就是为什么我需要这样的东西的背景 我正在处理Websocket上的JSON-RPC接口。这意味着请求-响应周期是完全异步的。当我发送一个请求时,我给它一个唯一的ID,异步响应包括该ID(以帮助将请求-响应联系在一起) 现在,我需要使用Aeson将JSON响应解析为Haskell对象。无论我以何种方式构造它,我都需要在代码中的某个点具有以下类型签名的函数: rpcId2HaskellType :: String -> a 其中,a并不是所有的类型,而是我期望得到

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

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

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

rpcId2HaskellType :: String -> a
其中,
a
并不是所有的类型,而是我期望得到的一些已知类型的响应

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

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

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

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

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


对于后一种情况,还有另一种使用存在数据类型的方法,但这几乎总是一个坏主意。它背后的想法并不可怕(在面向对象编程中非常常见),即让返回值“知道”如何处理它自己想要做的任何事情。然后你的代码就变成了要求它做那件事。不过,在FP中,通常最好让数据保持沉默。

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

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


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

我相信您要查找的是aeson中的typeclass

所以在您的例子中:
rpcId2HaskellType::FromJSON a=>String->a


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

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

所以在您的例子中:
rpcId2HaskellType::FromJSON a=>String->a


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

我只是猜测,因为我没有足够的信息来证明它,但我认为您问的问题不正确

我假设您的JSON-RPC如下所示:

request.json

{ message-id: "asec-ureh-asho-fcon-tent"
, content: { timestamp: "2016-01-31T10:23:10.123456"
           , command: { name: "mycommand"
                      , parameters: [..]
                      }
           }
}
{ message-id: "asec-ureh-asho-fthi-scon-tent"
, content: { timestamp: "2016-01-31T10:26:10.123456"
           , result: {..}
           , original-id: "asec-ureh-asho-fcon-tent"
           }
}
response.json

{ message-id: "asec-ureh-asho-fcon-tent"
, content: { timestamp: "2016-01-31T10:23:10.123456"
           , command: { name: "mycommand"
                      , parameters: [..]
                      }
           }
}
{ 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
消息id
,因为这只是内容的散列,这很可能是唯一的,因为它包含一个(唯一的)时间戳,只要您不考虑散列冲突

对于这个命令,我总是使用代数数据类型(ADT),因此我的服务器端逻辑是在haskell中捕获的,我想将“all”命令的执行限制在手头的集合中

我不认为你想避免为此编写ADT,但可能认为这太费劲了-这会让我避开你的问题找到答案,并建议你可能编写一些haskell模板,为你生成ADT

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


PPS.:
aeson
具有一些强大的功能,可以自动从JSON和
toJSON
实例派生
,请参阅

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

我假设您的JSON-RPC如下所示:

request.json

{ message-id: "asec-ureh-asho-fcon-tent"
, content: { timestamp: "2016-01-31T10:23:10.123456"
           , command: { name: "mycommand"
                      , parameters: [..]
                      }
           }
}
{ message-id: "asec-ureh-asho-fthi-scon-tent"
, content: { timestamp: "2016-01-31T10:26:10.123456"
           , result: {..}
           , original-id: "asec-ureh-asho-fcon-tent"
           }
}
response.json

{ message-id: "asec-ureh-asho-fcon-tent"
, content: { timestamp: "2016-01-31T10:23:10.123456"
           , command: { name: "mycommand"
                      , parameters: [..]
                      }
           }
}
{ 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
消息id
,因为这只是内容的散列,这很可能是唯一的,因为它包含一个(唯一的)时间戳,只要您不考虑散列冲突

对于这个命令,我总是使用代数数据类型(ADT),因此我的服务器端逻辑是在haskell中捕获的,我想将“all”命令的执行限制在手头的集合中

我不认为你想避免为此编写ADT,但可能认为这太费劲了-这会让我避开你的问题找到答案,并建议你可能编写一些haskell模板,为你生成ADT

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

PPS.:
aeson
具有一些强大的功能,可以自动从JSON
toJSON
实例派生
,请参阅

在哈斯克尔