Can my implementation of filter be improved?











up vote
6
down vote

favorite












An exercise in Haskell from First Principles says to implement filter using foldr and this is what I came up with but it feels and looks clunky. Is there a more natural way to implement it with a foldr?



import Data.Bool
myFilter :: (a -> Bool) -> [a] -> [a]
myFilter f = foldr (x -> bool (++ ) ((:) x) (f x))









share|improve this question


















  • 9




    (++) is just id.
    – Willem Van Onsem
    Nov 7 at 20:14






  • 3




    I'm not sure anyone would find ((:) x) less clunky than (x :).
    – chepner
    Nov 7 at 20:20










  • @chepner I changed that one a few seconds ago lol.
    – Brady Dean
    Nov 7 at 20:21






  • 1




    @chepner what do you mean? (⊢ never (is clunky (notation 'prefix)))
    – leftaroundabout
    Nov 7 at 20:24

















up vote
6
down vote

favorite












An exercise in Haskell from First Principles says to implement filter using foldr and this is what I came up with but it feels and looks clunky. Is there a more natural way to implement it with a foldr?



import Data.Bool
myFilter :: (a -> Bool) -> [a] -> [a]
myFilter f = foldr (x -> bool (++ ) ((:) x) (f x))









share|improve this question


















  • 9




    (++) is just id.
    – Willem Van Onsem
    Nov 7 at 20:14






  • 3




    I'm not sure anyone would find ((:) x) less clunky than (x :).
    – chepner
    Nov 7 at 20:20










  • @chepner I changed that one a few seconds ago lol.
    – Brady Dean
    Nov 7 at 20:21






  • 1




    @chepner what do you mean? (⊢ never (is clunky (notation 'prefix)))
    – leftaroundabout
    Nov 7 at 20:24















up vote
6
down vote

favorite









up vote
6
down vote

favorite











An exercise in Haskell from First Principles says to implement filter using foldr and this is what I came up with but it feels and looks clunky. Is there a more natural way to implement it with a foldr?



import Data.Bool
myFilter :: (a -> Bool) -> [a] -> [a]
myFilter f = foldr (x -> bool (++ ) ((:) x) (f x))









share|improve this question













An exercise in Haskell from First Principles says to implement filter using foldr and this is what I came up with but it feels and looks clunky. Is there a more natural way to implement it with a foldr?



import Data.Bool
myFilter :: (a -> Bool) -> [a] -> [a]
myFilter f = foldr (x -> bool (++ ) ((:) x) (f x))






haskell fold






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 7 at 20:13









Brady Dean

6911624




6911624








  • 9




    (++) is just id.
    – Willem Van Onsem
    Nov 7 at 20:14






  • 3




    I'm not sure anyone would find ((:) x) less clunky than (x :).
    – chepner
    Nov 7 at 20:20










  • @chepner I changed that one a few seconds ago lol.
    – Brady Dean
    Nov 7 at 20:21






  • 1




    @chepner what do you mean? (⊢ never (is clunky (notation 'prefix)))
    – leftaroundabout
    Nov 7 at 20:24
















  • 9




    (++) is just id.
    – Willem Van Onsem
    Nov 7 at 20:14






  • 3




    I'm not sure anyone would find ((:) x) less clunky than (x :).
    – chepner
    Nov 7 at 20:20










  • @chepner I changed that one a few seconds ago lol.
    – Brady Dean
    Nov 7 at 20:21






  • 1




    @chepner what do you mean? (⊢ never (is clunky (notation 'prefix)))
    – leftaroundabout
    Nov 7 at 20:24










9




9




(++) is just id.
– Willem Van Onsem
Nov 7 at 20:14




(++) is just id.
– Willem Van Onsem
Nov 7 at 20:14




3




3




I'm not sure anyone would find ((:) x) less clunky than (x :).
– chepner
Nov 7 at 20:20




I'm not sure anyone would find ((:) x) less clunky than (x :).
– chepner
Nov 7 at 20:20












@chepner I changed that one a few seconds ago lol.
– Brady Dean
Nov 7 at 20:21




@chepner I changed that one a few seconds ago lol.
– Brady Dean
Nov 7 at 20:21




1




1




@chepner what do you mean? (⊢ never (is clunky (notation 'prefix)))
– leftaroundabout
Nov 7 at 20:24






@chepner what do you mean? (⊢ never (is clunky (notation 'prefix)))
– leftaroundabout
Nov 7 at 20:24














4 Answers
4






active

oldest

votes

















up vote
5
down vote



accepted










I would only use bool if it let me get rid of the lambda expression simply, by composing a call to bool with the predicate p: bool iffalse iftrue . p. However, p isn't the only function that needs to be called on a list element; (:) does as well. You could use the Applicative instance for functions, to write



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


but in this case I would just use a plain if expression, inside the lambda expression:



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




Note that when specialized to functions, the Applicative's (<*>) operator is defined as f <*> g = x -> f x (g x). I leave it as an exercise to use that definition to transform bool id . (:) <*> p into
x -> bool id (x:) (p x).






share|improve this answer



















  • 2




    That applicative code is indeed quite obfuscated. I also greatly prefer the plain code below.
    – chi
    Nov 7 at 21:32


















up vote
2
down vote













You can use the Applicative instance of (->) a to make the lambda cleaner. But, if you want to use foldr, I don't think there's any substantial change you can effect:



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


bool id <$> (:) <*> f means x -> bool id ((:) x) (f x). bool id has type ([a] -> [a]) -> Bool -> ([a] -> [a]). (:) has type a -> [a] -> [a], and f has type a -> Bool. When (<$>) and (<*>) are used in this way, you can think of it as pretending that (:) and f don't have an a argument, making them [a] -> [a] and Bool, respectively, applying them to bool id to get a [a] -> [a], and then ending the lie by reintroducing the a argument, making a a -> [a] -> [a]. The operators are in charge of threading that a around, so you don't need a lambda abstraction.






share|improve this answer





















  • I'm not familiar with Applicative yet but thanks for the answer.
    – Brady Dean
    Nov 7 at 20:52


















up vote
1
down vote













Rather than merely searching for a more elegant implementation, it would might help you more to learn an elegant process of searching for an implementation. This should make it simpler to find elegant solutions.



For any function h on lists we have that,



h = foldr f e 


if and only if



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


In this case your h is filter p for some boolean function p that selects which elements to keep. Implementing filter p as a "simple" recursive function is not too hard.



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


The 1st line implies e = . The 2nd line needs to be written in the form f x (filter p xs) to match the equation of h above, in order for us to deduce which f to plug in the foldr. To do that we just abstract over those two expressions.



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


So we have found that,



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


It therefore follows,



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


To learn more about this method of working with foldr I recommend reading
"A tutorial on the universality and expressiveness of fold" by Graham Hutton.



Some added notes:



In case this seems overly complicated, note that while the principles above can be used in this "semi rigorous" fashion via algebraic manipulation, they can and should also be used to guide your intuition and aid you in informal development.



The equation for h (x:xs) = f x (h xs) sheds some clarity on how to find f. In the case where h is the filtering function you want an f which combines the element x with a tail that has already been filtered. If you really understand this it should be easy to arrive at,



f x ys = if p x then x : ys else ys





share|improve this answer



















  • 1




    did you perhaps mean f y ys = if p y then y : ys else ys in the last line? BTW it can also be written f y ys = [y | p y] ++ ys.
    – Will Ness
    Nov 8 at 15:48












  • ops missed that, I thought x would be clearer in that context but forgot to change the p y to p x
    – Jorge Adriano
    Nov 8 at 17:19










  • I also sensed some Richard Bird in there, esp. at the start, from his "theory of lists"... :) is it so?
    – Will Ness
    Nov 8 at 17:24












  • Possibly, since my very first book on Haskell was his classic "Introduction to Functional Programming using Haskell", but never read that particular paper to be honest.
    – Jorge Adriano
    Nov 8 at 17:52


















up vote
0
down vote













Yes, there is:



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

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


See, I switched it on you, with foldMap.



Well, with foldr it is foldr (x -> ([x | f x] ++)) .






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53197120%2fcan-my-implementation-of-filter-be-improved%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    5
    down vote



    accepted










    I would only use bool if it let me get rid of the lambda expression simply, by composing a call to bool with the predicate p: bool iffalse iftrue . p. However, p isn't the only function that needs to be called on a list element; (:) does as well. You could use the Applicative instance for functions, to write



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


    but in this case I would just use a plain if expression, inside the lambda expression:



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




    Note that when specialized to functions, the Applicative's (<*>) operator is defined as f <*> g = x -> f x (g x). I leave it as an exercise to use that definition to transform bool id . (:) <*> p into
    x -> bool id (x:) (p x).






    share|improve this answer



















    • 2




      That applicative code is indeed quite obfuscated. I also greatly prefer the plain code below.
      – chi
      Nov 7 at 21:32















    up vote
    5
    down vote



    accepted










    I would only use bool if it let me get rid of the lambda expression simply, by composing a call to bool with the predicate p: bool iffalse iftrue . p. However, p isn't the only function that needs to be called on a list element; (:) does as well. You could use the Applicative instance for functions, to write



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


    but in this case I would just use a plain if expression, inside the lambda expression:



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




    Note that when specialized to functions, the Applicative's (<*>) operator is defined as f <*> g = x -> f x (g x). I leave it as an exercise to use that definition to transform bool id . (:) <*> p into
    x -> bool id (x:) (p x).






    share|improve this answer



















    • 2




      That applicative code is indeed quite obfuscated. I also greatly prefer the plain code below.
      – chi
      Nov 7 at 21:32













    up vote
    5
    down vote



    accepted







    up vote
    5
    down vote



    accepted






    I would only use bool if it let me get rid of the lambda expression simply, by composing a call to bool with the predicate p: bool iffalse iftrue . p. However, p isn't the only function that needs to be called on a list element; (:) does as well. You could use the Applicative instance for functions, to write



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


    but in this case I would just use a plain if expression, inside the lambda expression:



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




    Note that when specialized to functions, the Applicative's (<*>) operator is defined as f <*> g = x -> f x (g x). I leave it as an exercise to use that definition to transform bool id . (:) <*> p into
    x -> bool id (x:) (p x).






    share|improve this answer














    I would only use bool if it let me get rid of the lambda expression simply, by composing a call to bool with the predicate p: bool iffalse iftrue . p. However, p isn't the only function that needs to be called on a list element; (:) does as well. You could use the Applicative instance for functions, to write



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


    but in this case I would just use a plain if expression, inside the lambda expression:



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




    Note that when specialized to functions, the Applicative's (<*>) operator is defined as f <*> g = x -> f x (g x). I leave it as an exercise to use that definition to transform bool id . (:) <*> p into
    x -> bool id (x:) (p x).







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 9 at 17:00









    Will Ness

    42k467118




    42k467118










    answered Nov 7 at 20:47









    chepner

    238k29223318




    238k29223318








    • 2




      That applicative code is indeed quite obfuscated. I also greatly prefer the plain code below.
      – chi
      Nov 7 at 21:32














    • 2




      That applicative code is indeed quite obfuscated. I also greatly prefer the plain code below.
      – chi
      Nov 7 at 21:32








    2




    2




    That applicative code is indeed quite obfuscated. I also greatly prefer the plain code below.
    – chi
    Nov 7 at 21:32




    That applicative code is indeed quite obfuscated. I also greatly prefer the plain code below.
    – chi
    Nov 7 at 21:32












    up vote
    2
    down vote













    You can use the Applicative instance of (->) a to make the lambda cleaner. But, if you want to use foldr, I don't think there's any substantial change you can effect:



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


    bool id <$> (:) <*> f means x -> bool id ((:) x) (f x). bool id has type ([a] -> [a]) -> Bool -> ([a] -> [a]). (:) has type a -> [a] -> [a], and f has type a -> Bool. When (<$>) and (<*>) are used in this way, you can think of it as pretending that (:) and f don't have an a argument, making them [a] -> [a] and Bool, respectively, applying them to bool id to get a [a] -> [a], and then ending the lie by reintroducing the a argument, making a a -> [a] -> [a]. The operators are in charge of threading that a around, so you don't need a lambda abstraction.






    share|improve this answer





















    • I'm not familiar with Applicative yet but thanks for the answer.
      – Brady Dean
      Nov 7 at 20:52















    up vote
    2
    down vote













    You can use the Applicative instance of (->) a to make the lambda cleaner. But, if you want to use foldr, I don't think there's any substantial change you can effect:



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


    bool id <$> (:) <*> f means x -> bool id ((:) x) (f x). bool id has type ([a] -> [a]) -> Bool -> ([a] -> [a]). (:) has type a -> [a] -> [a], and f has type a -> Bool. When (<$>) and (<*>) are used in this way, you can think of it as pretending that (:) and f don't have an a argument, making them [a] -> [a] and Bool, respectively, applying them to bool id to get a [a] -> [a], and then ending the lie by reintroducing the a argument, making a a -> [a] -> [a]. The operators are in charge of threading that a around, so you don't need a lambda abstraction.






    share|improve this answer





















    • I'm not familiar with Applicative yet but thanks for the answer.
      – Brady Dean
      Nov 7 at 20:52













    up vote
    2
    down vote










    up vote
    2
    down vote









    You can use the Applicative instance of (->) a to make the lambda cleaner. But, if you want to use foldr, I don't think there's any substantial change you can effect:



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


    bool id <$> (:) <*> f means x -> bool id ((:) x) (f x). bool id has type ([a] -> [a]) -> Bool -> ([a] -> [a]). (:) has type a -> [a] -> [a], and f has type a -> Bool. When (<$>) and (<*>) are used in this way, you can think of it as pretending that (:) and f don't have an a argument, making them [a] -> [a] and Bool, respectively, applying them to bool id to get a [a] -> [a], and then ending the lie by reintroducing the a argument, making a a -> [a] -> [a]. The operators are in charge of threading that a around, so you don't need a lambda abstraction.






    share|improve this answer












    You can use the Applicative instance of (->) a to make the lambda cleaner. But, if you want to use foldr, I don't think there's any substantial change you can effect:



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


    bool id <$> (:) <*> f means x -> bool id ((:) x) (f x). bool id has type ([a] -> [a]) -> Bool -> ([a] -> [a]). (:) has type a -> [a] -> [a], and f has type a -> Bool. When (<$>) and (<*>) are used in this way, you can think of it as pretending that (:) and f don't have an a argument, making them [a] -> [a] and Bool, respectively, applying them to bool id to get a [a] -> [a], and then ending the lie by reintroducing the a argument, making a a -> [a] -> [a]. The operators are in charge of threading that a around, so you don't need a lambda abstraction.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 7 at 20:45









    HTNW

    9,0941732




    9,0941732












    • I'm not familiar with Applicative yet but thanks for the answer.
      – Brady Dean
      Nov 7 at 20:52


















    • I'm not familiar with Applicative yet but thanks for the answer.
      – Brady Dean
      Nov 7 at 20:52
















    I'm not familiar with Applicative yet but thanks for the answer.
    – Brady Dean
    Nov 7 at 20:52




    I'm not familiar with Applicative yet but thanks for the answer.
    – Brady Dean
    Nov 7 at 20:52










    up vote
    1
    down vote













    Rather than merely searching for a more elegant implementation, it would might help you more to learn an elegant process of searching for an implementation. This should make it simpler to find elegant solutions.



    For any function h on lists we have that,



    h = foldr f e 


    if and only if



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


    In this case your h is filter p for some boolean function p that selects which elements to keep. Implementing filter p as a "simple" recursive function is not too hard.



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


    The 1st line implies e = . The 2nd line needs to be written in the form f x (filter p xs) to match the equation of h above, in order for us to deduce which f to plug in the foldr. To do that we just abstract over those two expressions.



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


    So we have found that,



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


    It therefore follows,



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


    To learn more about this method of working with foldr I recommend reading
    "A tutorial on the universality and expressiveness of fold" by Graham Hutton.



    Some added notes:



    In case this seems overly complicated, note that while the principles above can be used in this "semi rigorous" fashion via algebraic manipulation, they can and should also be used to guide your intuition and aid you in informal development.



    The equation for h (x:xs) = f x (h xs) sheds some clarity on how to find f. In the case where h is the filtering function you want an f which combines the element x with a tail that has already been filtered. If you really understand this it should be easy to arrive at,



    f x ys = if p x then x : ys else ys





    share|improve this answer



















    • 1




      did you perhaps mean f y ys = if p y then y : ys else ys in the last line? BTW it can also be written f y ys = [y | p y] ++ ys.
      – Will Ness
      Nov 8 at 15:48












    • ops missed that, I thought x would be clearer in that context but forgot to change the p y to p x
      – Jorge Adriano
      Nov 8 at 17:19










    • I also sensed some Richard Bird in there, esp. at the start, from his "theory of lists"... :) is it so?
      – Will Ness
      Nov 8 at 17:24












    • Possibly, since my very first book on Haskell was his classic "Introduction to Functional Programming using Haskell", but never read that particular paper to be honest.
      – Jorge Adriano
      Nov 8 at 17:52















    up vote
    1
    down vote













    Rather than merely searching for a more elegant implementation, it would might help you more to learn an elegant process of searching for an implementation. This should make it simpler to find elegant solutions.



    For any function h on lists we have that,



    h = foldr f e 


    if and only if



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


    In this case your h is filter p for some boolean function p that selects which elements to keep. Implementing filter p as a "simple" recursive function is not too hard.



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


    The 1st line implies e = . The 2nd line needs to be written in the form f x (filter p xs) to match the equation of h above, in order for us to deduce which f to plug in the foldr. To do that we just abstract over those two expressions.



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


    So we have found that,



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


    It therefore follows,



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


    To learn more about this method of working with foldr I recommend reading
    "A tutorial on the universality and expressiveness of fold" by Graham Hutton.



    Some added notes:



    In case this seems overly complicated, note that while the principles above can be used in this "semi rigorous" fashion via algebraic manipulation, they can and should also be used to guide your intuition and aid you in informal development.



    The equation for h (x:xs) = f x (h xs) sheds some clarity on how to find f. In the case where h is the filtering function you want an f which combines the element x with a tail that has already been filtered. If you really understand this it should be easy to arrive at,



    f x ys = if p x then x : ys else ys





    share|improve this answer



















    • 1




      did you perhaps mean f y ys = if p y then y : ys else ys in the last line? BTW it can also be written f y ys = [y | p y] ++ ys.
      – Will Ness
      Nov 8 at 15:48












    • ops missed that, I thought x would be clearer in that context but forgot to change the p y to p x
      – Jorge Adriano
      Nov 8 at 17:19










    • I also sensed some Richard Bird in there, esp. at the start, from his "theory of lists"... :) is it so?
      – Will Ness
      Nov 8 at 17:24












    • Possibly, since my very first book on Haskell was his classic "Introduction to Functional Programming using Haskell", but never read that particular paper to be honest.
      – Jorge Adriano
      Nov 8 at 17:52













    up vote
    1
    down vote










    up vote
    1
    down vote









    Rather than merely searching for a more elegant implementation, it would might help you more to learn an elegant process of searching for an implementation. This should make it simpler to find elegant solutions.



    For any function h on lists we have that,



    h = foldr f e 


    if and only if



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


    In this case your h is filter p for some boolean function p that selects which elements to keep. Implementing filter p as a "simple" recursive function is not too hard.



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


    The 1st line implies e = . The 2nd line needs to be written in the form f x (filter p xs) to match the equation of h above, in order for us to deduce which f to plug in the foldr. To do that we just abstract over those two expressions.



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


    So we have found that,



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


    It therefore follows,



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


    To learn more about this method of working with foldr I recommend reading
    "A tutorial on the universality and expressiveness of fold" by Graham Hutton.



    Some added notes:



    In case this seems overly complicated, note that while the principles above can be used in this "semi rigorous" fashion via algebraic manipulation, they can and should also be used to guide your intuition and aid you in informal development.



    The equation for h (x:xs) = f x (h xs) sheds some clarity on how to find f. In the case where h is the filtering function you want an f which combines the element x with a tail that has already been filtered. If you really understand this it should be easy to arrive at,



    f x ys = if p x then x : ys else ys





    share|improve this answer














    Rather than merely searching for a more elegant implementation, it would might help you more to learn an elegant process of searching for an implementation. This should make it simpler to find elegant solutions.



    For any function h on lists we have that,



    h = foldr f e 


    if and only if



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


    In this case your h is filter p for some boolean function p that selects which elements to keep. Implementing filter p as a "simple" recursive function is not too hard.



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


    The 1st line implies e = . The 2nd line needs to be written in the form f x (filter p xs) to match the equation of h above, in order for us to deduce which f to plug in the foldr. To do that we just abstract over those two expressions.



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


    So we have found that,



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


    It therefore follows,



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


    To learn more about this method of working with foldr I recommend reading
    "A tutorial on the universality and expressiveness of fold" by Graham Hutton.



    Some added notes:



    In case this seems overly complicated, note that while the principles above can be used in this "semi rigorous" fashion via algebraic manipulation, they can and should also be used to guide your intuition and aid you in informal development.



    The equation for h (x:xs) = f x (h xs) sheds some clarity on how to find f. In the case where h is the filtering function you want an f which combines the element x with a tail that has already been filtered. If you really understand this it should be easy to arrive at,



    f x ys = if p x then x : ys else ys






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 8 at 19:47

























    answered Nov 8 at 12:56









    Jorge Adriano

    43624




    43624








    • 1




      did you perhaps mean f y ys = if p y then y : ys else ys in the last line? BTW it can also be written f y ys = [y | p y] ++ ys.
      – Will Ness
      Nov 8 at 15:48












    • ops missed that, I thought x would be clearer in that context but forgot to change the p y to p x
      – Jorge Adriano
      Nov 8 at 17:19










    • I also sensed some Richard Bird in there, esp. at the start, from his "theory of lists"... :) is it so?
      – Will Ness
      Nov 8 at 17:24












    • Possibly, since my very first book on Haskell was his classic "Introduction to Functional Programming using Haskell", but never read that particular paper to be honest.
      – Jorge Adriano
      Nov 8 at 17:52














    • 1




      did you perhaps mean f y ys = if p y then y : ys else ys in the last line? BTW it can also be written f y ys = [y | p y] ++ ys.
      – Will Ness
      Nov 8 at 15:48












    • ops missed that, I thought x would be clearer in that context but forgot to change the p y to p x
      – Jorge Adriano
      Nov 8 at 17:19










    • I also sensed some Richard Bird in there, esp. at the start, from his "theory of lists"... :) is it so?
      – Will Ness
      Nov 8 at 17:24












    • Possibly, since my very first book on Haskell was his classic "Introduction to Functional Programming using Haskell", but never read that particular paper to be honest.
      – Jorge Adriano
      Nov 8 at 17:52








    1




    1




    did you perhaps mean f y ys = if p y then y : ys else ys in the last line? BTW it can also be written f y ys = [y | p y] ++ ys.
    – Will Ness
    Nov 8 at 15:48






    did you perhaps mean f y ys = if p y then y : ys else ys in the last line? BTW it can also be written f y ys = [y | p y] ++ ys.
    – Will Ness
    Nov 8 at 15:48














    ops missed that, I thought x would be clearer in that context but forgot to change the p y to p x
    – Jorge Adriano
    Nov 8 at 17:19




    ops missed that, I thought x would be clearer in that context but forgot to change the p y to p x
    – Jorge Adriano
    Nov 8 at 17:19












    I also sensed some Richard Bird in there, esp. at the start, from his "theory of lists"... :) is it so?
    – Will Ness
    Nov 8 at 17:24






    I also sensed some Richard Bird in there, esp. at the start, from his "theory of lists"... :) is it so?
    – Will Ness
    Nov 8 at 17:24














    Possibly, since my very first book on Haskell was his classic "Introduction to Functional Programming using Haskell", but never read that particular paper to be honest.
    – Jorge Adriano
    Nov 8 at 17:52




    Possibly, since my very first book on Haskell was his classic "Introduction to Functional Programming using Haskell", but never read that particular paper to be honest.
    – Jorge Adriano
    Nov 8 at 17:52










    up vote
    0
    down vote













    Yes, there is:



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

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


    See, I switched it on you, with foldMap.



    Well, with foldr it is foldr (x -> ([x | f x] ++)) .






    share|improve this answer

























      up vote
      0
      down vote













      Yes, there is:



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

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


      See, I switched it on you, with foldMap.



      Well, with foldr it is foldr (x -> ([x | f x] ++)) .






      share|improve this answer























        up vote
        0
        down vote










        up vote
        0
        down vote









        Yes, there is:



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

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


        See, I switched it on you, with foldMap.



        Well, with foldr it is foldr (x -> ([x | f x] ++)) .






        share|improve this answer












        Yes, there is:



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

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


        See, I switched it on you, with foldMap.



        Well, with foldr it is foldr (x -> ([x | f x] ++)) .







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 8 at 17:23









        Will Ness

        42k467118




        42k467118






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53197120%2fcan-my-implementation-of-filter-be-improved%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            鏡平學校

            ꓛꓣだゔៀៅຸ໢ທຮ໕໒ ,ໂ'໥໓າ໼ឨឲ៵៭ៈゎゔit''䖳𥁄卿' ☨₤₨こゎもょの;ꜹꟚꞖꞵꟅꞛေၦေɯ,ɨɡ𛃵𛁹ޝ޳ޠ޾,ޤޒޯ޾𫝒𫠁သ𛅤チョ'サノބޘދ𛁐ᶿᶇᶀᶋᶠ㨑㽹⻮ꧬ꧹؍۩وَؠ㇕㇃㇪ ㇦㇋㇋ṜẰᵡᴠ 軌ᵕ搜۳ٰޗޮ޷ސޯ𫖾𫅀ल, ꙭ꙰ꚅꙁꚊꞻꝔ꟠Ꝭㄤﺟޱސꧨꧼ꧴ꧯꧽ꧲ꧯ'⽹⽭⾁⿞⼳⽋២៩ញណើꩯꩤ꩸ꩮᶻᶺᶧᶂ𫳲𫪭𬸄𫵰𬖩𬫣𬊉ၲ𛅬㕦䬺𫝌𫝼,,𫟖𫞽ហៅ஫㆔ాఆఅꙒꚞꙍ,Ꙟ꙱エ ,ポテ,フࢰࢯ𫟠𫞶 𫝤𫟠ﺕﹱﻜﻣ𪵕𪭸𪻆𪾩𫔷ġ,ŧآꞪ꟥,ꞔꝻ♚☹⛵𛀌ꬷꭞȄƁƪƬșƦǙǗdžƝǯǧⱦⱰꓕꓢႋ神 ဴ၀க௭எ௫ឫោ ' េㇷㇴㇼ神ㇸㇲㇽㇴㇼㇻㇸ'ㇸㇿㇸㇹㇰㆣꓚꓤ₡₧ ㄨㄟ㄂ㄖㄎ໗ツڒذ₶।ऩछएोञयूटक़कयँृी,冬'𛅢𛅥ㇱㇵㇶ𥄥𦒽𠣧𠊓𧢖𥞘𩔋цѰㄠſtʯʭɿʆʗʍʩɷɛ,əʏダヵㄐㄘR{gỚṖḺờṠṫảḙḭᴮᵏᴘᵀᵷᵕᴜᴏᵾq﮲ﲿﴽﭙ軌ﰬﶚﶧ﫲Ҝжюїкӈㇴffצּ﬘﭅﬈軌'ffistfflſtffतभफɳɰʊɲʎ𛁱𛁖𛁮𛀉 𛂯𛀞నఋŀŲ 𫟲𫠖𫞺ຆຆ ໹້໕໗ๆทԊꧢꧠ꧰ꓱ⿝⼑ŎḬẃẖỐẅ ,ờỰỈỗﮊDžȩꭏꭎꬻ꭮ꬿꭖꭥꭅ㇭神 ⾈ꓵꓑ⺄㄄ㄪㄙㄅㄇstA۵䞽ॶ𫞑𫝄㇉㇇゜軌𩜛𩳠Jﻺ‚Üမ႕ႌႊၐၸဓၞၞၡ៸wyvtᶎᶪᶹစဎ꣡꣰꣢꣤ٗ؋لㇳㇾㇻㇱ㆐㆔,,㆟Ⱶヤマފ޼ޝަݿݞݠݷݐ',ݘ,ݪݙݵ𬝉𬜁𫝨𫞘くせぉて¼óû×ó£…𛅑הㄙくԗԀ5606神45,神796'𪤻𫞧ꓐ㄁ㄘɥɺꓵꓲ3''7034׉ⱦⱠˆ“𫝋ȍ,ꩲ軌꩷ꩶꩧꩫఞ۔فڱێظペサ神ナᴦᵑ47 9238їﻂ䐊䔉㠸﬎ffiﬣ,לּᴷᴦᵛᵽ,ᴨᵤ ᵸᵥᴗᵈꚏꚉꚟ⻆rtǟƴ𬎎

            Why https connections are so slow when debugging (stepping over) in Java?