2010-10-24 4 views
1

Im un étudiant qui est vraiment nouveau à la programmation fonctionnelle. Im travaillant sur une application bancaire où les données ont déjà été définies comme,Comment trier la liste par son accountID en utilisant le tri rapide dans Haskell

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)] 

Im essayant de trier la liste par son numéro de compte en utilisant le code suivant,

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 

Mais je n'obtenir le résultat attendu. comme il me donne une erreur, en informant "Instance de Ord Accounttype nécessaire pour la définition de viewSortedDetails". S'il vous plaît quelqu'un peut m'aider à surmonter ce problème Merci beaucoup!

Répondre

6

Eh bien, le problème est que vous utilisez des comparaisons la commande, tels que <=, sur deux Account valeurs, qui ont besoin Account être une instance de Ord. Maintenant, Account est un synonyme pour un tuple à quatre éléments, qui sont définis comme étant des instances de Ord lorsque tous les types dans le tuple sont. Accountno, Name, et Accountamount sont tous les synonymes pour les types avec Ord instances, mais Accounttype ne sont pas.

Vous pouvez permettre de trier Account valeurs directement en faisant Accounttype une instance de Ord, que vous pouvez le faire en ajoutant simplement à la clause deriving. Cependant, si vous voulez trier spécifiquement seulement par le numéro de compte, pas les autres éléments du tuple, vous devrez faire quelque chose différemment. Une option serait de faire Account un type de données avec une coutume Ord exemple:

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

instance Ord Account where 
    (...) 

Ensuite, vous pouvez définir l'ordre comme bon vous semble.

Alternativement, vous pouvez le laisser tel quel et au lieu que comparer l'élément que vous voulez au lieu de la valeur totale Account, en utilisant quelque chose comme ceci:

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

... et puis en faisant la comparaison avec quelque chose comme smallerSorted = sortByID [x | x <- ls, accountNo x <= accountNo l]. Les bibliothèques standard incluent également une fonction on à cet effet, mais il serait difficile à utiliser dans ce cas.


Quelques autres remarques, qui sont moins pertinentes à votre question, sur le sujet général du Code Haskell:

  • Définition Account comme type de données, en utilisant probablement la syntaxe d'enregistrement, seraient plus agréable que d'utiliser un synonyme de type ici. Les grandes tuples peuvent être difficiles à travailler.

  • Accountno et Accountamount devrait probablement être différents types et pour éviter de les mélanger avec d'autres Int s: la première parce que faire des calculs sur les numéros de compte peu de sens, celui-ci en partie parce que (je devine) vous » re implicitement en utilisant l'arithmétique de point fixe, de telle sorte que 100 signifie en réalité 1.00, et en général juste pour éviter la confusion.

  • En fait, Int est probablement un mauvais choix pour Accountamount de toute façon: Pourquoi ne pas quelque chose de Data.Fixed, Ratio Integer, ou un type à virgule flottante base 10-safe (bien qu'il n'y ait pas une dans les bibliothèques standard, malheureusement) . Les bibliothèques standard incluent bien sûr des fonctions de tri - je suppose que la réimplémentation est à des fins d'apprentissage, mais en pratique, elle pourrait être remplacée par quelque chose comme sortBy (compare `on` accountNo).

+0

Merci beaucoup pour votre réponse. Beaucoup apprécié. J'ai essayé la deuxième méthode que vous avez mentionnée. Mais encore il me donne une erreur d'information, le type inféré n'est pas assez général *** Expression: sortByID *** Type attendu: Ord a => [a] -> [a] *** Type déduit: Ord (Int, [Char], Type de compte, Int) => [(Int, [Char], Type de compte, Int)] -> [(Int, [Char], Accounttype, Int)] Pouvez-vous être assez aimable pour m'aider avec cette . Encore une fois merci beaucoup. – user421607

+0

@ user421607: Extraire un élément du tuple met plus de restrictions sur le type en cours de tri: Il nécessite une liste de 'Account', pas une liste générique comme' [a] '. Si vous supprimez simplement la signature de type, elle devrait en déduire la bonne, mais '[Account] -> [Account]' devrait être ce qu'elle veut. –

+0

Je me suis fatigué de cette manière aussi ... Mais ça m'a quand même donné des erreurs. J'essaie d'abord ta méthode. Merci beaucoup pour l'aide. – user421607