我是一名真正擅长函数式编程的学生。我正在开发一个已经定义为数据的银行应用程序,
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实例”。请帮助我克服这个问题 非常感谢!
答案 0 :(得分:6)
嗯,问题是你在两个<=
值上使用排序比较,例如Account
,这需要Account
成为Ord
的实例}。现在,Account
是四元素元组的同义词,当元组中的所有类型都被定义为Ord
的实例时。 Accountno
,Name
和Accountamount
都是包含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
定义为数据类型(可能使用记录语法)比使用类型同义词更好。大元组可能很难处理。
Accountno
和Accountamount
也应该是不同的类型,以避免将它们与其他Int
混合:首先是因为对帐号进行算术没有意义,后者部分是因为(我猜)你隐含地使用定点运算,这样100实际上意味着1.00,而且通常只是为了避免混淆。
事实上,Int
可能是Accountamount
的错误选择:为什么不是来自Data.Fixed
,Ratio Integer
或基数为10的安全内容浮点类型(不幸的是,标准库中没有一个)。
标准库当然包括排序函数 - 我假设重新实现是为了学习目的,但在实践中它可以被sortBy (compare `on` accountNo)
之类的东西取代。