Peut ma mise en œuvre du filtre à améliorer?

voix
6

Un exercice de Haskell de Principes dit à mettre en œuvre à l' filteraide foldret ce que je suis venu avec mais il se sent et semble maladroit. Est - il possible de mettre en œuvre plus naturelle avec un foldr?

import Data.Bool
myFilter :: (a -> Bool) -> [a] -> [a]
myFilter f = foldr (\x -> bool (++ []) ((:) x) (f x)) []
Créé 07/11/2018 à 20:13
source utilisateur
Dans d'autres langues...                            


4 réponses

voix
5

Je ne l' utiliser boolsi elle me laisse se débarrasser de la simple expression lambda, en composant un appel à boolavec le prédicat p: bool iffalse iftrue . p. Cependant, pn'est pas la seule fonction qui doit être appelée sur un élément de la liste; (:)fait aussi bien. Vous pouvez utiliser l' Applicativeexemple pour les fonctions, d'écrire

myfilter p = foldr (bool id . (:) <*> p) []  -- yuck

mais dans ce cas , je voudrais simplement utiliser une plaine ifexpression, dans l'expression lambda:

myfilter p = foldr (\x -> if p x then (x:) else id) []  -- much clearer!

Notez que lorsque spécialisés aux fonctions, le Applicative« s ' (<*>)opérateur est défini comme f <*> g = \x -> f x (g x). Je laisse comme un exercice d'utiliser cette définition pour transformer bool id . (:) <*> pen \x -> bool id (x:) (p x).

Créé 07/11/2018 à 20:47
source utilisateur

voix
2

Vous pouvez utiliser l' Applicativeinstance de (->) afaire le nettoyeur lambda. Mais, si vous voulez utiliser foldr, je ne pense pas qu'il y ait un changement important , vous pouvez effectuer:

myFilter f = foldr (bool id <$> (:) <*> f) []

bool id <$> (:) <*> fsignifie \x -> bool id ((:) x) (f x). bool ida le type ([a] -> [a]) -> Bool -> ([a] -> [a]). (:)est de type a -> [a] -> [a], et fa le type a -> Bool. Quand (<$>)et (<*>)sont utilisés de cette façon, vous pouvez penser comme prétendre que (:)et fne dispose pas d' un aargument qui les rend [a] -> [a]et Bool, respectivement, en les appliquant à bool idobtenir un [a] -> [a], puis mettre fin au mensonge en réintroduisant l' aargumentation, ce qui a a -> [a] -> [a]. Les opérateurs sont en charge de threads qui aautour, de sorte que vous n'avez pas besoin d' une abstraction lambda.

Créé 07/11/2018 à 20:45
source utilisateur

voix
1

Plutôt que de chercher simplement une mise en œuvre plus élégante, il pourrait vous aider à apprendre plus un processus élégant de la recherche d'une mise en œuvre. Cela devrait rendre plus simple de trouver des solutions élégantes.

Pour toute fonction hsur les listes que nous avons que,

h = foldr f e 

si et seulement si

h [] = e
h (x:xs) = f x (h xs)

Dans ce cas , votre hest filter ppour une fonction booléenne pqui sélectionne les éléments à conserver. La mise en œuvre filter pen fonction récursive « simple » est pas trop difficile.

filter p [] = []
filter p (x:xs) = if p x then x : (filter p xs) else (filter p xs)

La 1ère ligne implique e = []. La 2ème ligne doit être écrit sous la forme f x (filter p xs)pour correspondre à l'équation hci - dessus, pour que nous puissions en déduire que fpour brancher le foldr. Pour ce faire , que nous venons de résumé sur ces deux expressions.

filter p [] = []
filter p (x:xs) = (\x ys -> if p x then x : ys else ys) x (filter p xs)

Nous avons donc constaté que,

e = [] 
f x ys = if p x then x: ys else ys

Il en résulte donc,

filter p = foldr (\y ys -> if p y then y : ys else ys) []

Pour en savoir plus sur cette méthode de travail avec foldrJe recommande la lecture « Un tutoriel sur l'universalité et l' expressivité du pli » par Graham Hutton.

Quelques notes ajoutées:

Dans le cas où cela semble trop compliqué, notez que si les principes ci-dessus peuvent être utilisés de cette façon « semi rigoureuse » par manipulation algébrique, ils peuvent et doivent également être utilisés pour guider votre intuition et vous aider dans le développement informel.

L'équation pour h (x:xs) = f x (h xs)jette un peu de clarté sur la façon de trouver f. Dans le cas où hest la fonction de filtrage vous voulez un fqui combine l'élément xavec une queue qui a déjà été filtrée. Si vous comprenez vraiment cela , il devrait être facile d'arriver à,

f x ys = if p x then x : ys else ys
Créé 08/11/2018 à 12:56
source utilisateur

voix
0

Oui il y a:

myFilter :: (a -> Bool) -> [a] -> [a]
myFilter f = foldMap (\x -> [x | f x])

> myFilter even [1..10]
[2,4,6,8,10]

Vous voyez, je vous l' alluma, avec foldMap.

Eh bien, avec foldrc'est foldr (\x -> ([x | f x] ++)) [].

Créé 08/11/2018 à 17:23
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more