使用代数数据类型合并列表

时间:2019-03-27 11:58:33

标签: haskell recursion pattern-matching algebraic-data-types

我试图了解创建的代数数据类型的语法。我创建的类型是[Int]Empty,与MaybeJustNothing相似,除了Just必须是Int的列表。当接受两个输入并提供相同类型的输出时,我很难理解如何操纵创建的类型。

data Example = Arg [Int]
         | Empty
    deriving Show

我使用模式匹配,并且了解每种情况都必须解决;但是,我的问题来自最终模式的语法,其中Empty都不是。我正在尝试编写两个函数:一个将[Int]构造函数中的两个Example列表组合在一起,并且我想创建一个仅显示一组[Int]并共享的函数,而不是合并。

第一个问题是结合两组。我可以在常规函数中执行此操作,但是在某个地方,使用Example数据类型,语法已关闭并且我不熟悉它。第二个最大的问题是相同的:我理解递归,但是我不理解在创建的数据类型中递归的语法。我还考虑在第二个函数中使用where语句,但是如果我无法正确获取基本递归的语法,那么我怀疑它会成功。

combine :: Example -> Example -> Example
combine Empty Empty = Empty
combine (Arg xs) Empty = (Arg xs)
combine Empty (Arg ys) = (Arg ys)
combine (Arg xs) (Arg ys) = Arg xs ++ ys

same :: Example -> Example -> Example
same _ Empty = Empty
same Empty _ = Empty
same (Arg x : xs) (Arg y : ys)
  | x == y    = x
  | otherwise = same (Arg xs) (Arg ys)

combine的输出应该是一个[Int]列表,其中包含两个列表中的所有Int;如果一个列表为空,则应返回整个非空列表。

same的输出应包含一个[Int]列表,该列表仅包含两个组共享的数字,不能重复;如果一组为空,则输出为空。

2 个答案:

答案 0 :(得分:1)

combine :: Example -> Example -> Example
combine x Empty = x
combine Empty x = x
combine (Arg xs) (Arg ys) = Arg $ union xs ys

union xs ys = nub $ xs ++ ys
nub [] = []
nub (x:xs) = if x `elem` xs then nub xs else x : nub xs

same :: Example -> Example -> Example
same _ Empty = Empty
same Empty _ = Empty
same (Arg xs) (Arg ys) = Arg $ intersect xs ys

intersect _ [] = [] -- unnecessary but practical!
intersect [] _ = []
intersect (x:xs) ys = if x `elem` ys then x : intersect xs ys else intersect xs ys

正如罗宾(Robin)所说,您有几个不同的问题。首先,您需要匹配所有情况,其次,您需要将结果包装回您的数据类型中,其次,您需要删除并集中的重复项,其次,您的“设置交集”操作仅适用于关于输入列表的结构。 unionintersect(在Data.List中也可用)足以用于演示目的而无需调用例如。 Data.IntSet.toList . Data.IntSet.fromList,尽管那样会更快。您的版本(如果稍有更正)将输出出现在两个列表中相同位置的元素。

关于函子的通用教程通常以Maybe开头,这可能对您有所帮助,因为ExampleMaybe [Int]同构。

您可能想使用Arg (x : xs)解构函数的示例是一个函数,该函数在两个列表的每个索引处获取较小的元素。你能尝试自己递归地写那个吗,即。不使用zip

编辑:重大更改和更正

答案 1 :(得分:0)

使用lifting的概念,我想到了这种解决方案:

import Data.List (nub)

data Example = Arg [Int]
         | Empty
    deriving Show

combine :: Example -> Example -> Example
combine Empty Empty = Empty
combine x Empty = x
combine Empty x = x
combine (Arg xs) (Arg ys) = Arg $ nub $ xs ++ ys

same :: Example -> Example -> Example
same arg1 arg2 = lift nub $ same' arg1 arg2
    where
        same' _ Empty = Empty
        same' Empty _ = Empty
        same' (Arg []) y = Arg []
        same' (Arg (x : xs)) (Arg (ys))
            | x `elem` ys = lift (x : ) $ same' (Arg xs) (Arg ys)
            | otherwise  = same' (Arg xs) (Arg ys)

lift :: ([Int] -> [Int]) -> Example -> Example
lift _ Empty = Empty
lift f (Arg x) = Arg (f x)

lift的作用是将功能应用于Arg的“内容”。如果您有表达式same (Arg [1, 2, 4, 3]) (Arg [3,1,4]),则递归会将其转换为:

lift nub $ lift (1 : ) $ lift (4 : ) $ lift (3 : ) $ Arg []

wich的估算结果如下:

lift nub $ lift (1 : ) $ lift (4 : ) $ Arg (3:[])
lift nub $ lift (1 : ) $ Arg (4:3:[])
lift nub $ Arg (1:4:3:[])
Arg (nub $ 1:4:3:[])

然后终于:

Arg [1,4,3]