繁体   English   中英

在 Haskell 中操作元组

[英]Manipulating Tuples in Haskell

我是 Haskell 的新手,我有一个关于元组的问题。 没有办法遍历元组吗? 我知道使用列表遍历非常容易,但是如果输入是作为元组给出的,那么是否没有办法像使用列表一样检查整个元组? 如果不是这种情况,是否可以仅将元组中的值提取到列表中并以这种方式执行遍历?

在 Haskell 中,将元组用作通用的可遍历容器不被认为是惯用的(也不是真的可能)。 您处理的任何元组都将具有固定数量的元素,这些元素的类型也是固定的。 (这与元组在例如 Python 中惯用的方式完全不同。)您询问“输入作为元组给出”的情况,但如果输入将具有灵活数量的元素,那么它肯定不会作为元组给出——列表是一个更有可能的选择。

这使得元组看起来不如其他一些语言灵活。 好处是您可以使用模式匹配来检查它们。 例如,如果您想为元组的每个元素评估某个谓词,并在所有谓词都通过时返回True ,您可以编写类似

all2 :: (a -> Bool) -> (a, a) -> Bool
all2 predicate (x, y) = predicate x && predicate y

或者,对于三元素元组,

all3 :: (a -> Bool) -> (a, a, a) -> Bool
all3 predicate (x, y, z) = predicate x && predicate y && predicate z

您可能会想,“等等,您需要为每个元组大小设置一个单独的函数?!” 是的,您确实这样做了,并且您可以开始了解为什么元组用例和列表用例之间没有很多重叠。 元组的优点正是他们那种呆板:你总是知道他们有多少值包含,以及什么类型的值有。 前者对于列表来说并不是真的。

没有办法遍历元组吗?

据我所知,没有内置的方法可以做到这一点。 写下遍历 2 元组、遍历 3 元组等的指令是很容易的,但这会有很大的限制,你只能处理元素都相同的元组类型。

map函数视为一个简单的示例。 只要您有一个函数a -> b您就可以将map应用于类型[a]的列表。 在这种情况下, map依次查看每个a值,将其传递给函数,并组装结果b值的列表。 但是对于元组,您可能拥有三个值都是不同类型的元素。 您的转换功能a s至b s是如果元组由两个不足够a值和c 如果您尝试开始写下Foldable实例或Traversable实例,即使只是对于二元素元组,您很快就会意识到这些类型类并非旨在处理其值可能具有不同类型的容器。

是否可以仅将元组中的值提取到列表中?

是的,但是对于输入元组的每个可能大小,您都需要一个单独的函数。 例如,

tupleToList2 :: (a, a) -> [a]
tupleToList2 (x, y) = [x, y]

tupleToList3 :: (a, a, a) -> [a]
tupleToList3 (x, y, z) = [x, y, z]

当然,好消息是您永远不会遇到必须处理任意大小的元组的情况,因为这在 Haskell 中不会发生。 想想接受任意大小元组的函数的类型签名:你怎么写?

在您接受元组作为输入的任何情况下,可能没有必要先将元组转换为列表,因为模式匹配语法意味着您可以单独处理元组的每个元素——而且您总是确切地知道会有多少这样的元素。

如果你的元组是同构元组,并且你不介意使用第三方包,那么lens提供了一些函数来遍历任意元组中的每个元素。

ghci> :m +Control.Lens
ghci> over each (*10) (1, 2, 3, 4, 5)   --traverse each element
(10,20,30,40,50)

Control.Lens.Tuple提供了一些镜头来获取和设置第 n 个元素到第 19 个。

您可以浏览lens包了解更多信息 如果你想学习lens包,Chris Penner 的Optics by examples是一本好书。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM