带有极简主义变化的工作版本,thx @Matt,Petr和Landei !!!
insert :: (Ord el) => el -> Menge el -> Menge el
insert a (Menge (x:xs)) = ins a (Menge (x:xs)) (Menge [])
ins a (Menge []) (Menge ys) = Menge (ys ++ [a])
ins a (Menge xs@(x:xs')) (Menge ys)
| a < x = Menge (ys ++ [a] ++ xs)
| a > x = ins a (Menge xs') (Menge (ys ++ [x]))
| otherwise = Menge (ys ++ xs)
有一个自己的数据类型Menge,就像一个列表,我应该在正确的位置插入一个元素......
module Menge (
Menge,
empty,
insert,
ins
) where
data Menge el = Menge [el] deriving (Eq)
instance (Show el) => Show (Menge el) where
show (Menge liste) = "{" ++ (elms liste) ++ "}"
where
elms :: (Show a) => [a] -> String
elms [] = ""
elms (x:[]) = show x
elms (x:xs) = show x ++ ", " ++ elms xs
empty :: Menge el
empty = Menge []
insert :: (Ord el) => el -> Menge el -> Menge el
--insert a (Menge []) = (Menge [a])
insert a (Menge (x:xs)) = ins a (Menge (x:xs)) (Menge [])
ins a (Menge []) (Menge (y:ys)) = (Menge ((y:ys) ++ [a]))
ins a (Menge (x:xs)) (Menge (y:ys))
| a < x = (Menge ((y:ys) ++ [a] ++ (x:xs)))
| a > x = ins a (Menge xs) (Menge ((y:ys) ++ [x]))
| a > x && xs == [] = error "same function as: ins a empty (Menge (y:ys))"
| a == x = (Menge ((y:ys) ++ (x:xs)))
| otherwise = error "blabla"
我输入:insert 2 (Menge ([1,3]))
,在我看来我的工作方式如下:
--> ins 2 (Menge (1:3)) empty --> 2 > 1 --> ins 2 (Menge [3]) (Menge [] ++ [1])
--> ins 2 (Menge [3]) (Menge [1]) --> 2 < 3 --> (Menge ([1] ++ [2] ++ [3])) --> [1,2,3]
但我得到:“函数中的非详尽模式”
如果我输入ins 2 (Menge ([1,3])) (Menge [])
,则会出现相同的错误,因此第一步有效。
似乎编译器不喜欢“empty”/“(Menge [])”,因为如果我输入:ins 2 (Menge ([1,3])) (Menge [1,3])
,我会得到{1, 3, 2}
作为答案。
答案 0 :(得分:3)
我发现ins
存在两个主要问题:
您似乎正在尝试使用empty
的值进行模式匹配 - 这不起作用。任何Menge
(包括具有非空列表的列表)都将匹配,因为empty
在此处用作函数的本地绑定(遮蔽其他绑定)。所以你需要改为:
ins a (Menge []) (Menge (y:ys)) = ...
此问题的一个症状是我的haskell安装在加载代码时向我发出pattern match(es) are overlapped
警告。这基本上意味着你有一些死代码。
你的模式与第三个参数Menge []
的时间不匹配 - 我认为,这是给出你所展示的信息的错误(虽然我不确定因为你没有给出完整的错误信息)。你的两个方程只匹配非空列表。
例如:
ghci> ins x (Menge []) (Menge [])
不符合任何模式。
答案 1 :(得分:1)
我尝试从头开始实施insert
。首先,我添加了函数unmenge
以使解构值更容易,并且还将Menge
声明修改为newtype(只是性能优化 - 这样,它实际上并不是在运行时创建一个新的数据构造函数。
newtype Menge el = Menge { unmenge :: [el] }
deriving (Eq)
现在,insert
函数可以写成如下:
insert :: (Ord el) => el -> Menge el -> Menge el
insert a (Menge []) = (Menge [a])
insert a (Menge xs@(x:xs'))
| a <= x = Menge (a : xs)
| otherwise = Menge (x : unmenge (insert a (Menge xs')))
如果a
小于列表中的第一项,则只是前置。如果不是,那么x
是最小的数字,因此它被放在第一位,a
被递归插入到其余部分。
请注意,此解决方案不是tail recursive。
更简单的解决方案是使用span
函数:
insert :: (Ord el) => el -> Menge el -> Menge el
insert a (Menge xs) = let (smaller, bigger) = span (<= a) xs
in Menge (smaller ++ [a] ++ bigger)
修改:您更正的代码似乎按预期工作。我简化了一点,但我没有改变任何实质性的东西:
insert :: (Ord el) => el -> Menge el -> Menge el
insert a (Menge (x:xs)) = ins a (Menge (x:xs)) (Menge [])
ins a (Menge []) (Menge ys) = Menge (ys ++ [a])
ins a (Menge xs@(x:xs')) (Menge ys)
| a < x = Menge (ys ++ [a] ++ xs)
| a > x = ins a (Menge xs') (Menge (ys ++ [x]))
| otherwise = Menge (ys ++ xs)
一些改进的想法:
在列表末尾追加元素具有 O(n)复杂性 - 必须重新计算整个列表。最好以相反的顺序保持列表,并且只在最后修复它:
ins a (Menge []) (Menge ys) = Menge (reverse ys ++ [a])
ins a (Menge xs@(x:xs')) (Menge ys)
| a < x = Menge (reverse (a : ys) ++ xs)
| a > x = ins a (Menge xs') (Menge (x : ys))
| otherwise = Menge (reverse ys ++ xs)
有一个名为Data.Set的数据结构可以满足您的需求:使用二叉树保留已排序的元素集。大多数操作都有 O(1)或 O(log n)复杂性。
答案 2 :(得分:1)
我的看法:
insert :: (Ord el) => el -> Menge el -> Menge el
insert a mx = merge (Menge [a]) mx
merge :: (Ord el) => Menge el -> Menge el -> Menge el
merge mx (Menge []) = mx
merge (Menge []) my = my
merge (Menge (x:xs)) (Menge (y:ys))
| x == y = merge (Menge xs) (Menge (y:ys))
| x < y = merge (Menge xs) (Menge (x:y:ys))
| x > y = let Menge zs = merge (Menge (x:xs)) (Menge ys)
in Menge (y:zs)