Haskell,自己的数据类型,将Element添加到排序列表中

时间:2012-08-13 17:28:24

标签: haskell types

带有极简主义变化的工作版本,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}作为答案。

3 个答案:

答案 0 :(得分:3)

我发现ins存在两个主要问题:

  1. 您似乎正在尝试使用empty的值进行模式匹配 - 这不起作用。任何Menge(包括具有非空列表的列表)都将匹配,因为empty在此处用作函数的本地绑定(遮蔽其他绑定)。所以你需要改为:

    ins a (Menge []) (Menge (y:ys)) = ...
    

    此问题的一个症状是我的haskell安装在加载代码时向我发出pattern match(es) are overlapped警告。这基本上意味着你有一些死代码。

  2. 你的模式与第三个参数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)

一些改进的想法:

  • 请看as-patterns(我在这里使用过它们)。
  • 在列表末尾追加元素具有 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)