从(值a,值b,值c)

时间:2017-11-04 22:19:06

标签: haskell tuples

我正在使用esqueleto进行SQL查询,我有一个查询返回类型为(Value a, Value b, Value c)的数据。我想从中提取(a, b, c)。我知道我可以像这样使用模式匹配:

let (Value a, Value b, Value c) = queryResult

但我想避免为每个元组元素重复Value。当元组具有更多元素(如10)时,这尤其令人讨厌。有什么方法可以简化这个吗?有没有我可以使用的功能:

let (a, b, c) = someFunction queryResult

3 个答案:

答案 0 :(得分:2)

该库似乎具有unValue功能,因此您只需选择一种映射任意长度元组的方法。然后someFunction可以成为

import Control.Lens (over, each)

someFunction = (over each) unValue

如果您想尝试其他方式来映射元组而不依赖镜头,可以查看以下问题:Haskell: how to map a tuple?

编辑:正如danidiaz所指出的,这只适用于最多8个字段长的元组。我不确定是否有更好的方法来概括它。

答案 1 :(得分:2)

如果您的元组具有所有相同的元素类型:

all3 :: (a -> b) -> (a, a, a) -> (b, b, b)
all3 f (x, y, z) = (f x, f y, f z)

这个案例可以用镜头抽象,使用@ {1}},如@ Zpalmtree的回答所述。

但是如果你的元组有不同的元素类型,你可以使用over each扩展名使这个函数的f参数变为多态:

RankNTypes

然后假设你有all3 :: (forall a. c a -> a) -> (c x, c y, c z) -> (x, y, z) all3 f (x, y, z) = (f x, f y, f z) ,你可以写:

unValue :: Value a -> a

但是,如果您有大元组,则需要编写单独的函数(a, b, c) = all3 unValue queryResult all4,...,all5。在这种情况下,您可以通过使用Template Haskell生成它们来减少样板。这是Haskell中通常避免使用大元组的部分原因,因为它们很难处理并且不能轻易地抽象出来。

答案 2 :(得分:1)

来自base

Data.Coerce提供coerce,其作为您的someFunction

coerce"交换" newtype为他们包装的基础类型(反之亦然)。即使它们被深深地包裹在其他类型中,这也可以工作。这也是零开销,因为newtype具有与它们包装的类型完全相同的运行时表示。

如果你感兴趣的话,你可以在the Wiki page上阅读关于类型变量角色的更多复杂性,但是这样的应用程序变得很简单,因为包使用&# 34;默认" Value类型变量参数的作用。