Send Beginners mailing list submissions to beginners@haskell.org To subscribe or unsubscribe via the World Wide Web, visit http://www.haskell.org/mailman/listinfo/beginners or, via email, send a message with subject or body 'help' to beginners-requ...@haskell.org
You can reach the person managing the list at beginners-ow...@haskell.org When replying, please edit your Subject line so it is more specific than "Re: Contents of Beginners digest..." Today's Topics: 1. Merge Sort Stack Overflow (Florian Lammel) 2. Fwd: Merge Sort Stack Overflow (Florian Lammel) 3. Re: Merge Sort Stack Overflow (Oscar Benjamin) 4. Re: Merge Sort Stack Overflow (Brandon Allbery) 5. Re: Merge Sort Stack Overflow (Oscar Benjamin) 6. Re: Merge Sort Stack Overflow (Chadda? Fouch?) ---------------------------------------------------------------------- Message: 1 Date: Mon, 16 Sep 2013 19:35:24 +0200 From: Florian Lammel <m...@florianlammel.com> To: Beginners@haskell.org Subject: [Haskell-beginners] Merge Sort Stack Overflow Message-ID: <CAAnRmS081F812_H7c__ipBDmVNS=n02rrmtkzfebsz4vaku...@mail.gmail.com> Content-Type: text/plain; charset="iso-8859-1" Hi, I've just started learning Haskell and am trying to implement some basic algorithms. My shot at merge sort looks like this: mergeSort :: Ord a => [a] -> [a] mergeSort [] = [] mergeSort [x] = [x] mergeSort xs = merge (mergeSort as) (mergeSort bs) where (as, bs) = splitInHalf xs splitInHalf :: [a] -> ([a], [a]) splitInHalf [] = ([], []) splitInHalf [x] = ([x], []) splitInHalf (x:y:xys) = (x:xs, y:ys) where (xs, ys) = splitInHalf xys merge :: Ord a => [a] -> [a] -> [a] merge xs [] = xs merge [] ys = ys merge (x:xs) (y:ys) = if x < y then x:(merge xs (y:ys)) else y:(merge ys (x:xs)) As far as I can tell, my implementation is more or less the same as on rosetta code [0], literate programs [1] and several stack overflow questions [2][3]. The algorithm works, but for large lists (for example, 500k random numbers), I get a stack overflow. So my question is: How can I change my code so that it works on larger inputs? Or, more generally, how can I write recursive algorithms in functional languages that require more nested function calls than fit in the stack? Regards Florian [0] http://rosettacode.org/wiki/Sorting_algorithms/Merge_sort#Haskell [1] http://en.literateprograms.org/Merge_sort_(Haskell) [2] http://stackoverflow.com/questions/7554226/haskell-merge-sort-sorting-words-and-numbers [3] http://stackoverflow.com/questions/1215432/merge-sort-in-haskell -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://www.haskell.org/pipermail/beginners/attachments/20130916/530a33af/attachment-0001.html> ------------------------------ Message: 2 Date: Mon, 16 Sep 2013 19:54:51 +0200 From: Florian Lammel <m...@florianlammel.com> To: beginners@haskell.org Subject: [Haskell-beginners] Fwd: Merge Sort Stack Overflow Message-ID: <CAAnRmS1jN7QGEEV2vj5eTjrVgmJm7nn5kOhqNLVN+ptZuM=a...@mail.gmail.com> Content-Type: text/plain; charset="iso-8859-1" Hi, I've just started learning Haskell and am trying to implement some basic algorithms. My shot at merge sort looks like this: mergeSort :: Ord a => [a] -> [a] mergeSort [] = [] mergeSort [x] = [x] mergeSort xs = merge (mergeSort as) (mergeSort bs) where (as, bs) = splitInHalf xs splitInHalf :: [a] -> ([a], [a]) splitInHalf [] = ([], []) splitInHalf [x] = ([x], []) splitInHalf (x:y:xys) = (x:xs, y:ys) where (xs, ys) = splitInHalf xys merge :: Ord a => [a] -> [a] -> [a] merge xs [] = xs merge [] ys = ys merge (x:xs) (y:ys) = if x < y then x:(merge xs (y:ys)) else y:(merge ys (x:xs)) As far as I can tell, my implementation is more or less the same as on rosetta code [0], literate programs [1] and several stack overflow questions [2][3]. The algorithm works, but for large lists (for example, 500k random numbers), I get a stack overflow. So my question is: How can I change my code so that it works on larger inputs? Or, more generally, how can I write recursive algorithms in functional languages that require more nested function calls than fit in the stack? Regards Florian [0] http://rosettacode.org/wiki/Sorting_algorithms/Merge_sort#Haskell [1] http://en.literateprograms.org/Merge_sort_(Haskell) [2] http://stackoverflow.com/questions/7554226/haskell-merge-sort-sorting-words-and-numbers [3] http://stackoverflow.com/questions/1215432/merge-sort-in-haskell -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://www.haskell.org/pipermail/beginners/attachments/20130916/f7bf77bb/attachment-0001.html> ------------------------------ Message: 3 Date: Mon, 16 Sep 2013 19:34:34 +0100 From: Oscar Benjamin <oscar.j.benja...@gmail.com> To: The Haskell-Beginners Mailing List - Discussion of primarily beginner-level topics related to Haskell <beginners@haskell.org> Subject: Re: [Haskell-beginners] Merge Sort Stack Overflow Message-ID: <cahvvxxtodujs9samkega793qamhebyvn_g32vn-x3ue689o...@mail.gmail.com> Content-Type: text/plain; charset=ISO-8859-1 On 16 September 2013 18:35, Florian Lammel <m...@florianlammel.com> wrote: > Hi, Hi Florian, > > I've just started learning Haskell and am trying to implement some basic > algorithms. I'm a beginner in Haskell as well so my advice may be corrected by someone else :) > My shot at merge sort looks like this: > > mergeSort :: Ord a => [a] -> [a] > mergeSort [] = [] > mergeSort [x] = [x] > mergeSort xs = merge (mergeSort as) (mergeSort bs) > where > (as, bs) = splitInHalf xs > > splitInHalf :: [a] -> ([a], [a]) > splitInHalf [] = ([], []) > splitInHalf [x] = ([x], []) > splitInHalf (x:y:xys) = (x:xs, y:ys) > where (xs, ys) = splitInHalf xys > > merge :: Ord a => [a] -> [a] -> [a] > merge xs [] = xs > merge [] ys = ys > merge (x:xs) (y:ys) = if x < y > then x:(merge xs (y:ys)) > else y:(merge ys (x:xs)) > > As far as I can tell, my implementation is more or less the same as on > rosetta code [0], literate programs [1] and several stack overflow questions > [2][3]. Well actually the Rosetta code link shows 3 different implementations and yours is the first of the three. Did you try the second one (the bottom up merge)? This is also what's used in the answer to the SO post [3] and according to the author there it's roughly what's used by ghc for Data.List.sort so it's presumably a good algorithm. > The algorithm works, but for large lists (for example, 500k random numbers), > I get a stack overflow. I'm not sure how this gets optimised but your call-stack is essentially as long as the input list. That's only going to work with such big inputs if the recursion is somehow optimised which I think happens because of lazy evaluation. However this depends on your merge function pulling a similar number of items from the 'as' list as from the 'bs' list. Otherwise (I think) you'll have a whole load of splitInHalf frames in the stack and maybe that gives your overflow. I may be *entirely* wrong but I think the problem comes from returning two lists from a function as you do in splitInHalf but then not consuming the same number of items from each at any one time. I don't think this can be optimised in quite the same lazy manner. It would be fine if you consumed from both lists in unison as in e.g. a merge-sum algorithm. > So my question is: How can I change my code so that it works on larger > inputs? Or, more generally, how can I write recursive algorithms in > functional languages that require more nested function calls than fit in the > stack? Have you tried the other algorithm from e..g Rosetta code? That one looks like it would work better in a lazy evaluation context since it just works sequentially on a list of lists. Oscar ------------------------------ Message: 4 Date: Mon, 16 Sep 2013 14:39:26 -0400 From: Brandon Allbery <allber...@gmail.com> To: The Haskell-Beginners Mailing List - Discussion of primarily beginner-level topics related to Haskell <beginners@haskell.org> Subject: Re: [Haskell-beginners] Merge Sort Stack Overflow Message-ID: <CAKFCL4Wzyamc851a3Re0oD8xzwbMKFQ-bwXmLinn=lkr8oc...@mail.gmail.com> Content-Type: text/plain; charset="utf-8" On Mon, Sep 16, 2013 at 2:34 PM, Oscar Benjamin <oscar.j.benja...@gmail.com>wrote: > I'm not sure how this gets optimised but your call-stack is GHC's stack is a pattern match stack, *not* a call stack. While implementations are allowed to differ in how they produce non-strict evaluation, GHC uses graph reduction; "calls" are not necessarily done in the order you would expect in a procedural language. -- brandon s allbery kf8nh sine nomine associates allber...@gmail.com ballb...@sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://www.haskell.org/pipermail/beginners/attachments/20130916/c84fe12b/attachment-0001.html> ------------------------------ Message: 5 Date: Mon, 16 Sep 2013 20:09:14 +0100 From: Oscar Benjamin <oscar.j.benja...@gmail.com> To: The Haskell-Beginners Mailing List - Discussion of primarily beginner-level topics related to Haskell <beginners@haskell.org> Subject: Re: [Haskell-beginners] Merge Sort Stack Overflow Message-ID: <CAHVvXxTK7-aihqNB9h8PA9nbva1Yi4j=4aboz7ca56yvw+k...@mail.gmail.com> Content-Type: text/plain; charset=ISO-8859-1 On 16 September 2013 19:39, Brandon Allbery <allber...@gmail.com> wrote: > On Mon, Sep 16, 2013 at 2:34 PM, Oscar Benjamin <oscar.j.benja...@gmail.com> > wrote: >> >> I'm not sure how this gets optimised but your call-stack is > > GHC's stack is a pattern match stack, *not* a call stack. While > implementations are allowed to differ in how they produce non-strict > evaluation, GHC uses graph reduction; "calls" are not necessarily done in > the order you would expect in a procedural language. Okay so I'm not so clear on the terminology that should be used for these things. My understanding is that lazy recursion over a list is fine in Haskell where it would be problematic in procedural languages, for example this function: timesTwo (x:xs) = 2*x:(timesTwo xs) recurses for every item in a list and could blow the stack for even small lists in a procedural language but is okay in Haskell. My understanding is that it's because it just evaluates whichever elements of the list are needed at the time so if you consume the list e.g. printing out the items then it never builds up any actual accumulating stack/heap of in-memory data during processing. However when you do this splitInHalf (x:y:xys) = (x:xs, y:ys) where (xs, ys) = splitInHalf xys and print out 1000s of values from one list and not the other then surely *something* has to build up in memory. How else would it remember which items belong in the other list? (This is what will happen when the OP tries to sort 500k random numbers since sqrt(500k) is roughly 1000.) Or am I still just not getting it? Oscar ------------------------------ Message: 6 Date: Mon, 16 Sep 2013 21:33:16 +0200 From: Chadda? Fouch? <chaddai.fou...@gmail.com> To: beginners <beginners@haskell.org> Subject: Re: [Haskell-beginners] Merge Sort Stack Overflow Message-ID: <canfjzra_k4l6bfissmdkg4jvz3cedac8mdmw1b9khslrcq+...@mail.gmail.com> Content-Type: text/plain; charset="utf-8" Le 16 sept. 2013 19:35, "Florian Lammel" <m...@florianlammel.com> a ?crit : > splitInHalf :: [a] -> ([a], [a]) > splitInHalf [] = ([], []) > splitInHalf [x] = ([x], []) > splitInHalf (x:y:xys) = (x:xs, y:ys) > where (xs, ys) = splitInHalf xys Try the following : > where ~(xs, ys) = splitInHalf xys And let us know if that help. -- Chadda? -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://www.haskell.org/pipermail/beginners/attachments/20130916/d2e2c2d2/attachment.html> ------------------------------ Subject: Digest Footer _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners ------------------------------ End of Beginners Digest, Vol 63, Issue 21 *****************************************