How would I split a string after the spaces in haskell?












-1















I know Haskell doesn't have loops, so I can't do that. I also know that recursion is "helpful" here, but that's about all I'm aware of.
So far, I've gotten a basic type signature, which is



toSplit :: String -> [String]


Basically, it changes from a string into a list of words...



Thanks!



P.S. I want to use the takeWhile and dropWhile functions... not a library...










share|improve this question




















  • 4





    Use words.

    – Willem Van Onsem
    Nov 24 '18 at 18:36






  • 4





    Entering that type signature into hoogle gives you two options: lines or words.

    – hnefatl
    Nov 24 '18 at 18:37













  • "...Haskell doesn't have loops..." Yes, because recursion replaces loops. This is why recursion is helpful here.

    – AJFarmar
    Nov 24 '18 at 19:24


















-1















I know Haskell doesn't have loops, so I can't do that. I also know that recursion is "helpful" here, but that's about all I'm aware of.
So far, I've gotten a basic type signature, which is



toSplit :: String -> [String]


Basically, it changes from a string into a list of words...



Thanks!



P.S. I want to use the takeWhile and dropWhile functions... not a library...










share|improve this question




















  • 4





    Use words.

    – Willem Van Onsem
    Nov 24 '18 at 18:36






  • 4





    Entering that type signature into hoogle gives you two options: lines or words.

    – hnefatl
    Nov 24 '18 at 18:37













  • "...Haskell doesn't have loops..." Yes, because recursion replaces loops. This is why recursion is helpful here.

    – AJFarmar
    Nov 24 '18 at 19:24
















-1












-1








-1


0






I know Haskell doesn't have loops, so I can't do that. I also know that recursion is "helpful" here, but that's about all I'm aware of.
So far, I've gotten a basic type signature, which is



toSplit :: String -> [String]


Basically, it changes from a string into a list of words...



Thanks!



P.S. I want to use the takeWhile and dropWhile functions... not a library...










share|improve this question
















I know Haskell doesn't have loops, so I can't do that. I also know that recursion is "helpful" here, but that's about all I'm aware of.
So far, I've gotten a basic type signature, which is



toSplit :: String -> [String]


Basically, it changes from a string into a list of words...



Thanks!



P.S. I want to use the takeWhile and dropWhile functions... not a library...







string haskell recursion






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 24 '18 at 18:44







ClaireBookworm

















asked Nov 24 '18 at 18:35









ClaireBookwormClaireBookworm

14




14








  • 4





    Use words.

    – Willem Van Onsem
    Nov 24 '18 at 18:36






  • 4





    Entering that type signature into hoogle gives you two options: lines or words.

    – hnefatl
    Nov 24 '18 at 18:37













  • "...Haskell doesn't have loops..." Yes, because recursion replaces loops. This is why recursion is helpful here.

    – AJFarmar
    Nov 24 '18 at 19:24
















  • 4





    Use words.

    – Willem Van Onsem
    Nov 24 '18 at 18:36






  • 4





    Entering that type signature into hoogle gives you two options: lines or words.

    – hnefatl
    Nov 24 '18 at 18:37













  • "...Haskell doesn't have loops..." Yes, because recursion replaces loops. This is why recursion is helpful here.

    – AJFarmar
    Nov 24 '18 at 19:24










4




4





Use words.

– Willem Van Onsem
Nov 24 '18 at 18:36





Use words.

– Willem Van Onsem
Nov 24 '18 at 18:36




4




4





Entering that type signature into hoogle gives you two options: lines or words.

– hnefatl
Nov 24 '18 at 18:37







Entering that type signature into hoogle gives you two options: lines or words.

– hnefatl
Nov 24 '18 at 18:37















"...Haskell doesn't have loops..." Yes, because recursion replaces loops. This is why recursion is helpful here.

– AJFarmar
Nov 24 '18 at 19:24







"...Haskell doesn't have loops..." Yes, because recursion replaces loops. This is why recursion is helpful here.

– AJFarmar
Nov 24 '18 at 19:24














2 Answers
2






active

oldest

votes


















3














If you want to implement that yourself, first thing you need to do is find the first word.
You can do that with:



takeWhile (/=' ') s


If the string starts with delimiter characters you need to trim those first. We can do that with dropWhile.



takeWhile (/=' ') $ dropWhile (==' ') s


Now we have the first word, but we also need the rest of the string starting after the first word, on which we will recurse. We can use splitAt:



(_, rest) = splitAt (length word) s


And then we recurse with the rest of the string and cons the first word onto the result of that recursion giving us a list of all words.



And we need to define the base case, the result for the empty string which will terminate the recursion once there are no more characters.



toSplit :: String -> [String]
toSplit "" =
toSplit s =
let word = takeWhile (/=' ') $ dropWhile (==' ') s
(_, rest) = splitAt (length word) s
in word : toSplit (dropWhile (==' ') rest)


Edit: There is a bug in the code above and it's not handling an edge case properly.



The bug is that it's calling splitAt on the original s but this gives a wrong result if s has leading spaces:



*Main> toSplit " foo"
["foo","o"]


This should fix the bug:



let trimmed = dropWhile (==' ') s
word = takeWhile (/=' ') trimmed
(_, rest) = splitAt (length word) trimmed


That leaves one edge case:



*Main> toSplit " "
[""]


One possible solution is to use a helper function:



toSplit :: String -> [String]
toSplit = splitWords . dropWhile (==' ')
where
splitWords "" =
splitWords s =
let word = takeWhile (/=' ') s
(_, rest) = splitAt (length word) s
in word : splitWords (dropWhile (==' ') rest)





share|improve this answer





















  • 2





    You can use span instead of takeWhile and splitAt

    – 4castle
    Nov 24 '18 at 19:41











  • Wow! Thanks!. @4castle In the question, I was asking about using takeWhile, but I definitely think that span would be good too.

    – ClaireBookworm
    Nov 24 '18 at 19:42





















1















I know Haskell doesn't have loops, so I can't do that. I also know
that recursion is "helpful" here...




Yes, Haskell use recursion rather then for, while loop structure that in imperative language.



In stead of write recursive function by myself, it is more common use map, foldr (foldl), unfoldr or etc recursively traverse the list. The advantage of these functions is that you can concentrate what want to do in step function. Like your question, is suitable use unfoldr to accomplish it.



Here is an example with takeWhile and dropWhile:



import Data.Char (isSpace)
import Data.List (unfoldr)

toSplit::String->[String]
toSplit = unfoldr step
where step = Nothing
step xs = Just (takeWhile (not . isSpace) xs,
(dropWhile isSpace . dropWhile (not . isSpace)) xs)


But a little bit verbose, use break function may be more readable like:



toSplit' = unfoldr step
where step = Nothing
step xs = let (word, rest) = break isSpace xs
in Just (word, dropWhile isSpace rest)





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',
    autoActivateHeartbeat: false,
    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%2f53461230%2fhow-would-i-split-a-string-after-the-spaces-in-haskell%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    If you want to implement that yourself, first thing you need to do is find the first word.
    You can do that with:



    takeWhile (/=' ') s


    If the string starts with delimiter characters you need to trim those first. We can do that with dropWhile.



    takeWhile (/=' ') $ dropWhile (==' ') s


    Now we have the first word, but we also need the rest of the string starting after the first word, on which we will recurse. We can use splitAt:



    (_, rest) = splitAt (length word) s


    And then we recurse with the rest of the string and cons the first word onto the result of that recursion giving us a list of all words.



    And we need to define the base case, the result for the empty string which will terminate the recursion once there are no more characters.



    toSplit :: String -> [String]
    toSplit "" =
    toSplit s =
    let word = takeWhile (/=' ') $ dropWhile (==' ') s
    (_, rest) = splitAt (length word) s
    in word : toSplit (dropWhile (==' ') rest)


    Edit: There is a bug in the code above and it's not handling an edge case properly.



    The bug is that it's calling splitAt on the original s but this gives a wrong result if s has leading spaces:



    *Main> toSplit " foo"
    ["foo","o"]


    This should fix the bug:



    let trimmed = dropWhile (==' ') s
    word = takeWhile (/=' ') trimmed
    (_, rest) = splitAt (length word) trimmed


    That leaves one edge case:



    *Main> toSplit " "
    [""]


    One possible solution is to use a helper function:



    toSplit :: String -> [String]
    toSplit = splitWords . dropWhile (==' ')
    where
    splitWords "" =
    splitWords s =
    let word = takeWhile (/=' ') s
    (_, rest) = splitAt (length word) s
    in word : splitWords (dropWhile (==' ') rest)





    share|improve this answer





















    • 2





      You can use span instead of takeWhile and splitAt

      – 4castle
      Nov 24 '18 at 19:41











    • Wow! Thanks!. @4castle In the question, I was asking about using takeWhile, but I definitely think that span would be good too.

      – ClaireBookworm
      Nov 24 '18 at 19:42


















    3














    If you want to implement that yourself, first thing you need to do is find the first word.
    You can do that with:



    takeWhile (/=' ') s


    If the string starts with delimiter characters you need to trim those first. We can do that with dropWhile.



    takeWhile (/=' ') $ dropWhile (==' ') s


    Now we have the first word, but we also need the rest of the string starting after the first word, on which we will recurse. We can use splitAt:



    (_, rest) = splitAt (length word) s


    And then we recurse with the rest of the string and cons the first word onto the result of that recursion giving us a list of all words.



    And we need to define the base case, the result for the empty string which will terminate the recursion once there are no more characters.



    toSplit :: String -> [String]
    toSplit "" =
    toSplit s =
    let word = takeWhile (/=' ') $ dropWhile (==' ') s
    (_, rest) = splitAt (length word) s
    in word : toSplit (dropWhile (==' ') rest)


    Edit: There is a bug in the code above and it's not handling an edge case properly.



    The bug is that it's calling splitAt on the original s but this gives a wrong result if s has leading spaces:



    *Main> toSplit " foo"
    ["foo","o"]


    This should fix the bug:



    let trimmed = dropWhile (==' ') s
    word = takeWhile (/=' ') trimmed
    (_, rest) = splitAt (length word) trimmed


    That leaves one edge case:



    *Main> toSplit " "
    [""]


    One possible solution is to use a helper function:



    toSplit :: String -> [String]
    toSplit = splitWords . dropWhile (==' ')
    where
    splitWords "" =
    splitWords s =
    let word = takeWhile (/=' ') s
    (_, rest) = splitAt (length word) s
    in word : splitWords (dropWhile (==' ') rest)





    share|improve this answer





















    • 2





      You can use span instead of takeWhile and splitAt

      – 4castle
      Nov 24 '18 at 19:41











    • Wow! Thanks!. @4castle In the question, I was asking about using takeWhile, but I definitely think that span would be good too.

      – ClaireBookworm
      Nov 24 '18 at 19:42
















    3












    3








    3







    If you want to implement that yourself, first thing you need to do is find the first word.
    You can do that with:



    takeWhile (/=' ') s


    If the string starts with delimiter characters you need to trim those first. We can do that with dropWhile.



    takeWhile (/=' ') $ dropWhile (==' ') s


    Now we have the first word, but we also need the rest of the string starting after the first word, on which we will recurse. We can use splitAt:



    (_, rest) = splitAt (length word) s


    And then we recurse with the rest of the string and cons the first word onto the result of that recursion giving us a list of all words.



    And we need to define the base case, the result for the empty string which will terminate the recursion once there are no more characters.



    toSplit :: String -> [String]
    toSplit "" =
    toSplit s =
    let word = takeWhile (/=' ') $ dropWhile (==' ') s
    (_, rest) = splitAt (length word) s
    in word : toSplit (dropWhile (==' ') rest)


    Edit: There is a bug in the code above and it's not handling an edge case properly.



    The bug is that it's calling splitAt on the original s but this gives a wrong result if s has leading spaces:



    *Main> toSplit " foo"
    ["foo","o"]


    This should fix the bug:



    let trimmed = dropWhile (==' ') s
    word = takeWhile (/=' ') trimmed
    (_, rest) = splitAt (length word) trimmed


    That leaves one edge case:



    *Main> toSplit " "
    [""]


    One possible solution is to use a helper function:



    toSplit :: String -> [String]
    toSplit = splitWords . dropWhile (==' ')
    where
    splitWords "" =
    splitWords s =
    let word = takeWhile (/=' ') s
    (_, rest) = splitAt (length word) s
    in word : splitWords (dropWhile (==' ') rest)





    share|improve this answer















    If you want to implement that yourself, first thing you need to do is find the first word.
    You can do that with:



    takeWhile (/=' ') s


    If the string starts with delimiter characters you need to trim those first. We can do that with dropWhile.



    takeWhile (/=' ') $ dropWhile (==' ') s


    Now we have the first word, but we also need the rest of the string starting after the first word, on which we will recurse. We can use splitAt:



    (_, rest) = splitAt (length word) s


    And then we recurse with the rest of the string and cons the first word onto the result of that recursion giving us a list of all words.



    And we need to define the base case, the result for the empty string which will terminate the recursion once there are no more characters.



    toSplit :: String -> [String]
    toSplit "" =
    toSplit s =
    let word = takeWhile (/=' ') $ dropWhile (==' ') s
    (_, rest) = splitAt (length word) s
    in word : toSplit (dropWhile (==' ') rest)


    Edit: There is a bug in the code above and it's not handling an edge case properly.



    The bug is that it's calling splitAt on the original s but this gives a wrong result if s has leading spaces:



    *Main> toSplit " foo"
    ["foo","o"]


    This should fix the bug:



    let trimmed = dropWhile (==' ') s
    word = takeWhile (/=' ') trimmed
    (_, rest) = splitAt (length word) trimmed


    That leaves one edge case:



    *Main> toSplit " "
    [""]


    One possible solution is to use a helper function:



    toSplit :: String -> [String]
    toSplit = splitWords . dropWhile (==' ')
    where
    splitWords "" =
    splitWords s =
    let word = takeWhile (/=' ') s
    (_, rest) = splitAt (length word) s
    in word : splitWords (dropWhile (==' ') rest)






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 25 '18 at 19:36

























    answered Nov 24 '18 at 19:05









    StefanStefan

    60028




    60028








    • 2





      You can use span instead of takeWhile and splitAt

      – 4castle
      Nov 24 '18 at 19:41











    • Wow! Thanks!. @4castle In the question, I was asking about using takeWhile, but I definitely think that span would be good too.

      – ClaireBookworm
      Nov 24 '18 at 19:42
















    • 2





      You can use span instead of takeWhile and splitAt

      – 4castle
      Nov 24 '18 at 19:41











    • Wow! Thanks!. @4castle In the question, I was asking about using takeWhile, but I definitely think that span would be good too.

      – ClaireBookworm
      Nov 24 '18 at 19:42










    2




    2





    You can use span instead of takeWhile and splitAt

    – 4castle
    Nov 24 '18 at 19:41





    You can use span instead of takeWhile and splitAt

    – 4castle
    Nov 24 '18 at 19:41













    Wow! Thanks!. @4castle In the question, I was asking about using takeWhile, but I definitely think that span would be good too.

    – ClaireBookworm
    Nov 24 '18 at 19:42







    Wow! Thanks!. @4castle In the question, I was asking about using takeWhile, but I definitely think that span would be good too.

    – ClaireBookworm
    Nov 24 '18 at 19:42















    1















    I know Haskell doesn't have loops, so I can't do that. I also know
    that recursion is "helpful" here...




    Yes, Haskell use recursion rather then for, while loop structure that in imperative language.



    In stead of write recursive function by myself, it is more common use map, foldr (foldl), unfoldr or etc recursively traverse the list. The advantage of these functions is that you can concentrate what want to do in step function. Like your question, is suitable use unfoldr to accomplish it.



    Here is an example with takeWhile and dropWhile:



    import Data.Char (isSpace)
    import Data.List (unfoldr)

    toSplit::String->[String]
    toSplit = unfoldr step
    where step = Nothing
    step xs = Just (takeWhile (not . isSpace) xs,
    (dropWhile isSpace . dropWhile (not . isSpace)) xs)


    But a little bit verbose, use break function may be more readable like:



    toSplit' = unfoldr step
    where step = Nothing
    step xs = let (word, rest) = break isSpace xs
    in Just (word, dropWhile isSpace rest)





    share|improve this answer






























      1















      I know Haskell doesn't have loops, so I can't do that. I also know
      that recursion is "helpful" here...




      Yes, Haskell use recursion rather then for, while loop structure that in imperative language.



      In stead of write recursive function by myself, it is more common use map, foldr (foldl), unfoldr or etc recursively traverse the list. The advantage of these functions is that you can concentrate what want to do in step function. Like your question, is suitable use unfoldr to accomplish it.



      Here is an example with takeWhile and dropWhile:



      import Data.Char (isSpace)
      import Data.List (unfoldr)

      toSplit::String->[String]
      toSplit = unfoldr step
      where step = Nothing
      step xs = Just (takeWhile (not . isSpace) xs,
      (dropWhile isSpace . dropWhile (not . isSpace)) xs)


      But a little bit verbose, use break function may be more readable like:



      toSplit' = unfoldr step
      where step = Nothing
      step xs = let (word, rest) = break isSpace xs
      in Just (word, dropWhile isSpace rest)





      share|improve this answer




























        1












        1








        1








        I know Haskell doesn't have loops, so I can't do that. I also know
        that recursion is "helpful" here...




        Yes, Haskell use recursion rather then for, while loop structure that in imperative language.



        In stead of write recursive function by myself, it is more common use map, foldr (foldl), unfoldr or etc recursively traverse the list. The advantage of these functions is that you can concentrate what want to do in step function. Like your question, is suitable use unfoldr to accomplish it.



        Here is an example with takeWhile and dropWhile:



        import Data.Char (isSpace)
        import Data.List (unfoldr)

        toSplit::String->[String]
        toSplit = unfoldr step
        where step = Nothing
        step xs = Just (takeWhile (not . isSpace) xs,
        (dropWhile isSpace . dropWhile (not . isSpace)) xs)


        But a little bit verbose, use break function may be more readable like:



        toSplit' = unfoldr step
        where step = Nothing
        step xs = let (word, rest) = break isSpace xs
        in Just (word, dropWhile isSpace rest)





        share|improve this answer
















        I know Haskell doesn't have loops, so I can't do that. I also know
        that recursion is "helpful" here...




        Yes, Haskell use recursion rather then for, while loop structure that in imperative language.



        In stead of write recursive function by myself, it is more common use map, foldr (foldl), unfoldr or etc recursively traverse the list. The advantage of these functions is that you can concentrate what want to do in step function. Like your question, is suitable use unfoldr to accomplish it.



        Here is an example with takeWhile and dropWhile:



        import Data.Char (isSpace)
        import Data.List (unfoldr)

        toSplit::String->[String]
        toSplit = unfoldr step
        where step = Nothing
        step xs = Just (takeWhile (not . isSpace) xs,
        (dropWhile isSpace . dropWhile (not . isSpace)) xs)


        But a little bit verbose, use break function may be more readable like:



        toSplit' = unfoldr step
        where step = Nothing
        step xs = let (word, rest) = break isSpace xs
        in Just (word, dropWhile isSpace rest)






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 25 '18 at 8:22

























        answered Nov 25 '18 at 7:32









        assembly.jcassembly.jc

        2,0891214




        2,0891214






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53461230%2fhow-would-i-split-a-string-after-the-spaces-in-haskell%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

            404 Error Contact Form 7 ajax form submitting

            How to know if a Active Directory user can login interactively

            TypeError: fit_transform() missing 1 required positional argument: 'X'