11

我知道有fstand snd,但是为什么没有使用类型类的访问器函数的“通用”定义?我会建议像

class Get1 p a | p -> a where
  get1 :: p -> a 

instance Get1 (a,b) a where
  get1 (x,_) = x 

instance Get1 (a,b,c) a where
  get1 (x,_,_) = x 

class Get2 p a | p -> a where
  get2 :: p -> a 

instance Get2 (a,b) b where
  get2 (_,x) = x 

instance Get2 (a,b,c) b where
  get2 (_,x,_) = x 

当然,你需要一些语言扩展,但这不是方便吗?特别是您可以为自己的类型添加实例。

4

2 回答 2

7

需要注意的一件事是,fstsnd允许一个查看 2 元组。将它们推广到其他领域和操作很快就会变得很痛苦。例如,如果您还想映射元组的第一个元素,则必须引入另一个组合子(据记录,该组合子存在于 2 元组中Control.Arrow.first)。这很快导致高元组的组合器数量激增。

话虽如此,lens提供了一些很好的工具来处理元组。Control.Lens.Tuple提供了几个索引透镜_1,_2等,它们允许访问元组的第一个、第二个等元素,直到 arity 9.

例如,

>>> import Control.Lens
>>> let t = (1,2,3,5,6,7,2)
>>> t ^._1
1
>>> t & _1 .~ 'a'
('a',2,3,5,6,7,2)
>>> t & _1 +~ 41
(42,2,3,5,6,7,2)
>>> over _1 (+1) t
(2,2,3,5,6,7,2)

您可能还对 中的元组实例感兴趣Control.Lens.At。此外,该tuple-lenses 软件包还提供了一些更通用的镜头,用于一次检查多个元组条目。

于 2013-03-12T12:28:28.127 回答
3

这样的类型类只提供编码(语法)便利,我看不到如何在它们之上构建泛化的元组类型工具。如果您正在寻找元组泛化,请查看Reddit 上关于异构向量的讨论。

另请注意,对于普通结构,最好定义自己的 ADT 并为 getter 提供合理的名称,然后使用高元组。

编辑:但是,正如 is7s 在评论中指出的那样,hackage 上有许多包为任意长度的元组提供索引功能。

于 2013-03-12T10:14:58.993 回答