Question

Je suis en train de comprendre le comportement de la fonction de la bibliothèque groupBy (de Data.List), qui prétend éléments du groupe d'une liste par une fonction « test d'égalité » adoptée en tant que premier argument. La signature de type suggère que le test d'égalité a juste besoin d'avoir le type

(a -> a -> Bool)

Cependant, quand je l'utilise (<) comme le "test d'égalité" dans GHCi 6.6, les résultats ne sont pas ce que je pense:

ghci> groupBy (<) [1, 2, 3, 2, 4, 1, 5, 9]
[[1,2,3,2,4],[1,5,9]]

Au lieu de cela, je me attends séries de chiffres strictement de plus en plus, comme ceci:

[[1,2,3],[2,4],[1,5,9]]

Qu'est-ce que je suis absent?

Était-ce utile?

La solution

Jetez un oeil à la GHC mise en œuvre de groupBy :

groupBy                 :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _  []           =  []
groupBy eq (x:xs)       =  (x:ys) : groupBy eq zs
                           where (ys,zs) = span (eq x) xs

Maintenant, comparez ces deux sorties:

Prelude List> groupBy (<) [1, 2, 3, 2, 4, 1, 5, 9]
[[1,2,3,2,4],[1,5,9]]
Prelude List> groupBy (<) [8, 2, 3, 2, 4, 1, 5, 9]
[[8],[2,3],[2,4],[1,5,9]]

En bref, ce qui se passe est ceci: groupBy suppose que les tests de fonction donnée (le premier argument) pour l'égalité, et suppose donc que la fonction de comparaison est réflexif , transitive et symétrique (voir équivalence relation ). Le problème ici est que le moins que relation n'est pas réfléchi, ni symétrique.


Modifier : La mise en œuvre suivante suppose que transitivité:

groupBy' :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy' _   []                        = []
groupBy' _   [x]                       = [[x]]
groupBy' cmp (x:xs@(x':_)) | cmp x x'  = (x:y):ys
                           | otherwise = [x]:r
  where r@(y:ys) = groupBy' cmp xs

Autres conseils

Le fait que "<" est pas un test d'égalité.

Vous pourriez vous attendre un comportement parce que vous souhaitez mettre en œuvre différemment, mais ce n'est pas ce qu'il promet.

Un exemple des raisons pour lesquelles ce qu'il est une réponse en sortie raisonnable est si elle balaye à travers elle, faire

[1, 2, 3, 2, 4, 1, 5, 9] ->
[[1,2,3], [2,4], [1,5,9]]

a maintenant 3 groupes d'éléments égaux. Donc, il vérifie si l'un d'entre eux sont en fait le même:

Comme il connaît tous les éléments de chaque groupe est égal, il peut juste regarder le premier élément de chaque, 1, 2 et 1.

1> 2? Oui! Ainsi, il fusionne les deux premiers groupes.

1> 1? Non! Ainsi, il quitte le dernier groupe soit.

Et maintenant, il est comparé tous les éléments pour l'égalité.

... seulement, vous n'avez pas réussi ce genre de fonction qu'il attend.

En bref, quand il veut un test d'égalité, donner il un test d'égalité.

scroll top