我试图了解创建的代数数据类型的语法。我创建的类型是[Int]
或Empty
,与Maybe
和Just
和Nothing
相似,除了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]
列表,该列表仅包含两个组共享的数字,不能重复;如果一组为空,则输出为空。
答案 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)所说,您有几个不同的问题。首先,您需要匹配所有情况,其次,您需要将结果包装回您的数据类型中,其次,您需要删除并集中的重复项,其次,您的“设置交集”操作仅适用于关于输入列表的结构。 union
,intersect
(在Data.List中也可用)足以用于演示目的而无需调用例如。 Data.IntSet.toList . Data.IntSet.fromList
,尽管那样会更快。您的版本(如果稍有更正)将输出出现在两个列表中相同位置的元素。
关于函子的通用教程通常以Maybe
开头,这可能对您有所帮助,因为Example
与Maybe [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]