【问题标题】:Pairing up elements from a list given a predicate在给定谓词的情况下将列表中的元素配对
【发布时间】:2020-11-01 00:37:42
【问题描述】:

我对 Haskell 比较陌生,并且发现了创建一组元组的挑战,这些元组贪婪地从给定谓词的列表中获取。例如,在[2,3,4,5,6,7] 上使用(\x -> \y -> odd(x+y)) 可以返回[(2,3),(3,2),(4,5),(5,4),(6,7),(7,6)][(2,7),(6,5),(3,4),(4,3),(5,6),(7,2)] 或任何其他有效的配对集合,只要它是每对对称的配对,并且该集合中的所有项目都包含在一个和只有一对。我挑战的一个关键部分是学习使用 monad,特别是 Maybe/Just/Nothing,所以我当前的函数是 Eq a => (a -> a -> Bool) -> [a] -> Maybe [(a,a)],如果无法制作包含每个元素的元组列表,则返回 Nothing;例如,在 [2,3,4,5,6,7] 上运行 (\x -> \y -> even(x+y)) 将返回 Nothing,因为您无法将所有元素配对以适应该谓词而不遗漏一些元素。

首先,我想我可以生成可能对的完整列表并使用谓词过滤它们。我目前的功能是test p xs = filter (uncurry p) [(x,y) | (x:ys) <- tails xs, y <- ys],我的想法是稍后我可以删除具有重复第一个值的元组(也许以某种方式使用nubBy?),从Data.Tuple 运行swap 在我的列表中剩下的内容上对对称,然后运行最终检查以查看列表中的所有元素是否都已包含在内,以便我知道是否不返回任何内容。然而,我意识到,可能有一种更好的方法来解决这个问题,它执行更少的冗余操作,并在更早的时候对返回 Nothing 进行最终检查。我尝试过使用列表理解,但我想不出任何有用的东西。

【问题讨论】:

  • 所以它应该总是选择匹配的“下一个”?
  • @WillemVanOnsem 理论上不,它可以以任何方式形成匹配,除了每次都取下一个可用数字之外,我想不出任何方法
  • 问题是现在看起来相当“不确定”。因为每个输入可以映射到多个输出。
  • @WillemVanOnsem 是的,我认为就是这样,只要我的函数找到其中一个,任何有效的输出都可以
  • 这里没有什么理由使用Maybe。在这种情况下,NothingJust [] 之间有什么显着区别?

标签: haskell


【解决方案1】:

元组(x, y) 本身是有序的:(x, y) != (y, x)。为过滤定义一个“无序”对类型会很有帮助:

newtype Pair x = Pair { unpair :: (x, x) }

instance Eq a => Eq (Pair a) where
  (Pair p1) == (Pair p2) = p1 == p2 || p1 == swap p2

然后您可以使用更简单的方法来生成样本对,将Applicative 实例用于列表。您可以稍后使用 Pair 过滤掉重复项。

>>> (,) <$> [1, 2, 3] <*> [1, 2, 3]
[(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]

过滤上述列表后,使用nub 首先将所有初始结果转换为Pair 值,使用nub 进行重复数据删除,然后再转换回元组:

result :: Eq x => [(x,x)] -> [(x,x)]
result = map unpair . nub . map Pair

【讨论】:

    猜你喜欢
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-04
    相关资源
    最近更新 更多