Haskell中任意数量的列表的并集

时间:2018-10-27 12:52:00

标签: haskell

如何在Haskell中获得任意数量的列表的并集。例如,我想要一个功能类似于以下功能的函数:

example1 = union' [1,2,3] [1,4]
example2 = union' [1,2,3] [1,4] [2,6]
example1
[1,2,3,4]
example2
[1,2,3,4,6]

2 个答案:

答案 0 :(得分:3)

Haskell中的一个函数仅接受一个参数。 “两个”参数函数实际上是返回另一个函数的函数,该函数返回最终返回值。因此,函数无法采用可变数量的参数,因为这样的函数的返回类型无法很好地定义。

如果要合并任意数量的列表,则函数应采用列表的 list ,因为列表可以包含任意数量的元素。

union' :: Eq a => [[a]] -> [a]
union' = foldr unionOfTwo []
  where unionOfTwo :: Eq a => [a] -> [a] -> [a]
        unionOfTwo xs ys = ...  -- left as an exercise

其中unionOfTwo知道如何精确地计算两个列表的结合。实际上,union'将输入中的第一个列表放在一边,递归计算其余输入的并集,然后计算该结果与原始第一个列表的并集。换句话说,

union' []  = []
union' (xs:xss) = unionOfTwo xs (union' xss)

答案 1 :(得分:2)

首先是一个工作代码示例:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
module Main where
import Data.List (union)

class Unionable a t where
  union' :: [a] -> t

instance  Unionable a [a] where
  union' = id

instance  (Eq a, Unionable a t) => Unionable a ([a] -> t) where
  union' xs ys = union' (union xs ys)

main = do
  print $ (union' [1::Integer,2,3] [1::Integer,5,6] [1::Integer,7,3] :: [Integer])

模仿here

您可能想将这样的函数与文字一起使用,可悲的是,如您在此处看到的那样,将其与多态文字一起使用并不方便,因为您需要指定每个参数的类型。

在其他情况下,参数的类型必须清楚,结果的预期类型也必须清楚,否则,您将需要添加此类类型注释。

对于普通代码来说,这可能不值得。

让我们解释一下这里发生的情况,编译器会看到:

(union' [1::Integer,2,3] [1::Integer,5,6] [1::Integer,7,3] :: [Integer])

它认为,我们需要

union' :: [Integer] -> [Integer] -> [Integer] -> [Integer]

我们有这样的union'吗?该实例的候选者将由第二实例声明提供

a ~ Integer
t ~ [Integer] -> [Integer] -> [Integer]

但要使该实例适用,我们需要一个具有这些分配的(Unionable a t)实例。我们有这样的实例吗?再次,第二个实例声明是一个候选,这次是

a ~ Integer
t ~ [Integer] -> [Integer]

但要使该实例适用,我们需要一个具有这些分配的(Unionable a t)实例。我们有这样的实例吗?再次,第二个实例声明是一个候选,这次是

a ~ Integer
t ~ [Integer]

这一次,我们从第一个实例声明中获得了这样一个实例, 无需其他限制。

这意味着(为了清楚起见,省略了类型注释)

union' [1,2,3] [1,5,6] [1,7,3]
= unions' (union [1,2,3] [1,5,6]) [1,7,3]
= unions' (union (union [1,2,3] [1,5,6]) [1,7,3])
= id (union (union [1,2,3] [1,5,6]) [1,7,3])
= (union (union [1,2,3] [1,5,6]) [1,7,3])
= [1,2,3,5,6,7]