Send Beginners mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Beginners digest..."
Today's Topics:
1. Re: list, map, sequence - stack overflow and performance
issues (Julian Ong)
----------------------------------------------------------------------
Message: 1
Date: Thu, 21 Jan 2021 07:12:33 +0000 (UTC)
From: Julian Ong <[email protected]>
To: The Haskell-Beginners Mailing List - Discussion of Primarily
Beginner-level Topics Related To Haskell <[email protected]>
Subject: Re: [Haskell-beginners] list, map, sequence - stack overflow
and performance issues
Message-ID: <[email protected]>
Content-Type: text/plain; charset="utf-8"
I have an update on my post. I implemented the same solution in Python 3 using
a dictionary and it ran pretty quickly. I couldn't understand why my similar
Haskell solution using an IntMap dictionary wasn't running similarly quickly.
I have been running Haskell code in GHCI. I decided to break the code for this
puzzle out into a separate file. Upon compiling and running, this code produced
the correct output relatively quickly, on par with the Python 3 version. I am
very surprised the code runs so much faster after compiling with GHC. I'm sure
this is obvious to experienced Haskellers but it was new to me that performance
could be so drastically different upon compilation, so I'm sharing in case
anyone else has run into something similar. Here is my Haskell code:
--- import Data.IntMap.Strict (IntMap)import qualified Data.IntMap.Strict as
IntMap
main = do let iterate' f x = x `seq` x : iterate' f (f x) print $ snd $
(iterate' nextNum (IntMap.fromList
[(9,1),(3,2),(1,3),(0,4),(8,5)],(4,6)))!!29999994
-- Uses Data.IntMap.Strict to keep track of each number that has appeared in
the list and its last position in an IntMap dictionarynextNum :: (IntMap Int,
(Int, Int)) -> (IntMap Int, (Int, Int))nextNum (mp, (k, v)) = case
IntMap.lookup k mp of Nothing -> (IntMap.insert k v mp, (0, v+1)) Just
pos -> (IntMap.insert k v mp, (v-pos, v+1))
On Saturday, January 16, 2021, 04:20:29 PM PST, Julian Ong
<[email protected]> wrote:
Sorry, corrected some typos below in the number of apostrophes.
On Saturday, January 16, 2021, 04:14:47 PM PST, Julian Ong
<[email protected]> wrote:
Hi Haskellers - I'm learning Haskell and attempting to solve the Advent of
Code 2020 puzzles using Haskell. I'm stuck on part 2 of Day 15 and have been
for a while now, so I'm reaching out.
The puzzle asks you to find the nth element in a list of integers. Here's how
the list is constructed:
Start with a seed list of integers, like [0,3,6]. Then, referring to the last
element (6), the next element is given by these rules:
- If the last element was the first time the element has appeared in the
list, then the next element is 0.
- Otherwise, the next element is the age, or distance in the number of index
positions, between the last element and when it last appeared before that.
For example, starting with [0,3,6], the next elements are 0, 3, 3, 1, 0, 4, 0,
etc.
Part 1 of the puzzle asks you to find the 2020th element in the list.
You can do this by constructing increasingly longer lists like this (using
Data.List):
nextNum :: [Int] -> [Int]nextNum l@(x:xs) = if not (x `elem` xs) then 0 : l
else age l : l where age (x:xs) = let Just i = elemIndex x xs
in i+1
Then:
head $ (iterate nextNum [6,3,0]) !! 2017
will give you the 2020th element of 436.
Note that you provide the starting list in reverse order and iterate so that it
will keep adding new elements to the head of the list, which is more efficient
than adding to the end.
You can also use unfoldr to generate the list element by element like this:
nextNum' :: [Int] -> IntnextNum' (x:xs) = if not (x `elem` xs) then 0 else age
x xs where age x xs = let Just i = elemIndex x xs
in i+1
Then:
(unfoldr (\l -> Just (nextNum' l, nextNum' l : l)) slist) !! 2016
will give you the 2020th element of 436.
---
Part 2 of the puzzle asks you to find the 30000000th element given starting
list [9,3,1,0,8,4].
I cannot find a way to do this without stack overflow and performance issues
(I've run my attempts overnight with no answer generated). I've tried using
Data.Map and Data.Sequence because my Stack Overflow searching suggested these
might be more efficient data structures for this sort of task. Here are my
attempts:
-- Uses Data.Map to avoid duplicate numbers thereby shortening the list. The
dictionary entry (k, v) gives the element and the last position of that element.
nextNum'' :: (IntMap Int, (Int, Int)) -> (IntMap Int, (Int, Int))nextNum''
(mp, (k, v)) = case IntMap.lookup k mp of Nothing -> (IntMap.insert k v mp,
(0, v+1)) Just pos -> (IntMap.insert k v mp, (v-pos, v+1))
Then:
snd $ (iterate nextNum'' (IntMap.fromList [(0,1),(3,2)],(6,3))) !! 2017
provides the answer for the 2020th element but either stack overflows or runs
for hours (if I use a strict version of iterate) trying to figure out the
30000000th element.
Similarly, using Data.Sequence, I tried:
nextNum''' :: Seq Int -> IntnextNum''' (xs :|> x) = if not (x `elem` xs) then
0 else age x xs where age x xs = let Just i = Seq.elemIndexR x xs
in Seq.length xs - i
aoc15b' :: Seq Int -> Int -> Intaoc15b' slist tnum = (\(xs :> x) -> x) $
Seq.viewr (Seq.unfoldr (\l -> if Seq.length l == tnum then Nothing else let
nnum = force (nextNum''' l) in Just (nnum, force (l |> nnum))) slist)
I found that I needed to fix stack overflow problems by using "force" from
Control.DeepSeq. Despite seemingly fixing stack overflow issues though, the
calculation just takes too long, and in fact, I have never been able to
actually output a solution.
I thought that using Data.Map or Data.Sequence would speed things up based on
my Stack Overflow searching, but I'm unable to come up with a Haskell solution
that runs in reasonable time.
I'm at a loss for different strategies at this point and would appreciate any
ideas from the community.
Thanks, Julian
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://mail.haskell.org/pipermail/beginners/attachments/20210121/32475453/attachment-0001.html>
------------------------------
Subject: Digest Footer
_______________________________________________
Beginners mailing list
[email protected]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
------------------------------
End of Beginners Digest, Vol 150, Issue 9
*****************************************