如何使用Haskell中的快速排序通过其accountID对列表进行排序

时间:2010-10-24 01:23:14

标签: sorting haskell functional-programming

我是一名真正擅长函数式编程的学生。我正在开发一个已经定义为数据的银行应用程序,

type Accountno = Int 
data Accounttype = Saving | Current  | FixedDeposit deriving (Show,Read)
type Accountamount = Int
type Name = String 
type Account = (Accountno, Name, Accounttype, Accountamount) 


exampleBase :: [Account]
exampleBase = [ (1,"Jennifer",Saving,1000 ) , 
    (5,"Melissa",Current,3000) ,
    (2,"Alex",Saving,1500)]

我尝试使用以下代码按照帐号对列表进行排序

sortByID :: (Ord a) => [a] -> [a]
sortByID [] = []
sortByID (l :ls) =
  let
   smallerSorted = sortByID [x | x <- ls, x <= l]
   biggerSorted = sortByID [x | x <- ls, x > l]
  in
   smallerSorted ++ [l] ++ biggerSorted


viewSortedDetails :: IO()
viewSortedDetails = 
    do
     putStrLn "Account Details Sorted By Account ID"
     let records = sortByID exampleBase
     let viewRecord = map show records
     mapM_ putStrLn viewRecord

但我没有得到预期的结果。因为它给了我一个错误,通知“定义viewSortedDetails所需的Ord Accounttype实例”。请帮助我克服这个问题 非常感谢!

1 个答案:

答案 0 :(得分:6)

嗯,问题是你在两个<=值上使用排序比较,例如Account,这需要Account成为Ord的实例}。现在,Account是四元素元组的同义词,当元组中的所有类型都被定义为Ord的实例时。 AccountnoNameAccountamount都是包含Ord个实例的类型的同义词,但Accounttype不是。

您可以通过Account Accounttype实例直接对Ord值进行排序,只需将其添加到deriving子句即可。

但是,如果您想通过帐号而不是元组的其他元素来专门对 进行排序,则需要采取不同的方式。一种选择是使Account成为具有自定义Ord实例的数据类型:

data Account = Account Accountno Name Accounttype Accountamount deriving (Eq, Show, Read)

instance Ord Account where
    (...)

然后你可以定义你想要的顺序。

或者,您可以保留原样,而只是比较您想要的元素而不是整个Account值,使用以下内容:

accountNo :: Account -> Accountno
accountNo (n,_,_,_) = n

...然后与smallerSorted = sortByID [x | x <- ls, accountNo x <= accountNo l]之类的东西进行比较。为此目的,标准库还包含一个函数on,但在这种情况下使用它会很麻烦。


关于Haskell代码的一般主题的一些其他与您的问题不太相关的评论:

  • Account定义为数据类型(可能使用记录语法)比使用类型同义词更好。大元组可能很难处理。

  • AccountnoAccountamount也应该是不同的类型,以避免将它们与其他Int混合:首先是因为对帐号进行算术没有意义,后者部分是因为(我猜)你隐含地使用定点运算,这样100实际上意味着1.00,而且通常只是为了避免混淆。

  • 事实上,Int可能是Accountamount的错误选择:为什么不是来自Data.FixedRatio Integer或基数为10的安全内容浮点类型(不幸的是,标准库中没有一个)。

  • 标准库当然包括排序函数 - 我假设重新实现是为了学习目的,但在实践中它可以被sortBy (compare `on` accountNo)之类的东西取代。

    < / LI>