I'm working on UPENN Haskell Homework 6 Exercise 5, trying to define a ruler function
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,...
where the nth element in the stream (assuming the first element corresponds to n = 1) is the largest power of 2 which evenly divides n.
I just came up with an idea to build it without any divisibility testing:
data Stream x = Cons x (Stream x) deriving (Eq)
streamRepeat x = Cons x (streamRepeat x)
interleaveStreams (Cons x xs) (Cons y ys) =
Cons x (Cons y (interleaveStreams xs ys))
ruler =
interleaveStreams (streamRepeat 0)
(interleaveStreams (streamRepeat 1)
(interleaveStreams (streamRepeat 2)
(interleaveStreams (streamRepeat 3) (...))
where first 20 element of
ruler =
interleaveStreams (streamRepeat 0)
(interleaveStreams (streamRepeat 1)
(interleaveStreams (streamRepeat 2)
(interleaveStreams (streamRepeat 3) (streamRepeat 4))))
is
[0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2]
Obviously I couldn't define it manually to infinite so I defined a infInterStream to help such infinite recursion definition:
infInterStream n = interleaveStreams (streamRepeat n) (infInterStream (n+1))
ruler = infInterStream 0
But now I get stuck when typing in ruler in ghci, it probably falls into infinite loop.
It shouldn't be if lazy evaluation works. I want to know why lazy evaluation fails here.
Helper function to observe Stream:
streamToList (Cons x xs) = x : streamToList xs
instance Show a => Show (Stream a) where
show = show . take 20 . streamToList
Your interleaving function is too strict. The following works:
interleaveStreams (Cons x xs) ys = Cons x (interleaveStreams ys xs)
This also works:
interleaveStreams (Cons x xs) ~(Cons y ys) =
Cons x (Cons y (interleaveStreams xs ys))
The original definition goes into infinite loop because interleaveStreams demands that both arguments must be of Cons forms. infInterStream n evaluates to the the interleaving of two streams, and the first one can be immediately evaluated to Cons, but the second one must also be reduced first to Cons, so we recursively call infInterStream (n + 1), which keeps calling itself ad infinitum.
If interleaveStreams can return a Cons a _ without first having to force the second argument, infInterStream can also incrementally build the result.
There's no need for a new type for streams, and we can just use Haskell's lazy lists instead. As others have noted, the definition of interleave must be sufficiently lazy that it can produce the first element of the output before testing whether the second argument is non-empty. This definition will do:
interleave (x:xs) ys = x : interleave ys xs
If you want interleave to work also for finite lists, you can add the equation
interleave [] ys = ys
Note also that, using functions from the standard prelude,
ruler = interleave (repeat 0) (map (+1) ruler)
Here repeat 0 is the list [0, 0, 0, ...].
Related
I have been going through the excellent CIS 194 course when I got stuck on Part 5 of Homework 6. It revolves around implementing the ruler function without any divisibility testing.
I found that it is possible to build the ruler function by continuously interspersing an accumulator with values from an infinite list.
nats = [0,1,2,3,..]
[3]
[2,3,2]
[1,2,1,3,1,2,1]
[0,1,0,2,0,1,0,3,0,1,0,2,0]
Then I tried implementing this algorithm for Stream datatype which is a list without nil
data Stream a = Cons a (Stream a)
streamToList :: Stream a -> [a]
streamToList (Cons x xs) = x : streamToList xs
instance Show a => Show (Stream a) where
show = show . take 20 . streamToList
streamFromSeed :: (a -> a) -> a -> Stream a
streamFromSeed f x = Cons x (streamFromSeed f (f x))
nats :: Stream Integer
nats = streamFromSeed succ 0
interleave x (Cons y ys) = Cons x (Cons y (interleave x ys))
foldStream f (Cons x xs) = f x (foldStream f xs)
ruler = foldStream interleave nats
As expected, I got stackoverflow error since I was trying to fold from the right. However, I was surprised to see the same algorithm work for normal infinite lists.
import Data.List
interleave x list = [x] ++ (intersperse x list) ++ [x]
ruler = take 20 (foldr interleave [] [0..])
What am I missing? Why one implementation works while the other doesn't?
Your interleave is insufficiently lazy. The magic thing that right folds must do to work on infinite structures is to not inspect the result of the folded value too closely before they do the first bit of computation. So:
interleave x stream = Cons x $ case stream of
Cons y ys -> Cons y (interleave x ys)
This produces Cons x _ before inspecting stream; in contrast, your version requires stream to be evaluated a bit before it can pass to the right hand side of the equation, which essentially forces the entire fold to happen before any constructor gets produced.
You can also see this in your list version of interleave:
interleave x list = [x] ++ intersperse x list ++ [x]
The first element of the returned list (x) is known before intersperse starts pattern matching on list.
We can inspect the source code of foldr [src]. A less noisy version looks like:
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
Haskell does not evaluate eagerly. This thus means that, unless you need (foldr f z xs), it will not evaluate the accumulator. This thus means that f does not need the second parameter, for example because the first item x has a certain value, it will not evaluate the accumulator.
For example if we implement takeWhileNeq:
takeWhileNeq a = foldr f []
where f x xs -> if x == a then [] else (x:xs)
if we thus run this on a list takeWhileNeq 2 [1,4,2,5], then it will not evaluate anything. If we however want to print the result it will evaluate this as:
f 1 (foldr f [4,2,5])
and f will inspect if 1 == 2, since that is not the case, it will return (x:xs), so:
-> 1 : foldr f [4,2,5]
so now it will evaluate 4 == 2, and because this is false, it will evaluate this to:
-> 1 : (4 : foldr f [2,5])
now we evaluate 2 == 2, and since this is True, the function returns the empty list, and ingores the accumulator, so it will never look at foldr f [5]:
-> 1 : (4 : [])
For an infinite list, it will thus also result an empty list and ignore folding the rest of the list.
This question already has answers here:
Haskell not lazy evaluating interleaving
(2 answers)
Fail to define an infinite stream
(2 answers)
Closed 3 years ago.
I am trying to implement exercise 5 of CIS 194 - Homework 6
This is my implementations;
data Stream a = Cons a (Stream a)
streamRepeat :: a -> Stream a
streamRepeat a = Cons a (streamRepeat a)
streamMap :: (a -> b) -> Stream a -> Stream b
streamMap f (Cons xval xlist) = Cons (f xval) (streamMap f xlist)
interleaveStreams :: Stream a -> Stream a -> Stream a
interleaveStreams (Cons afirst arest) (Cons bfirst brest) =
Cons afirst (Cons bfirst (interleaveStreams arest brest))
ruler :: Stream Integer
ruler = interleaveStreams (streamRepeat 0) (streamMap succ ruler)
However, when I try to get even the first value from the Stream, it hangs indefinitely. How can I make this recursive definition work lazily?
interleaveStreams is strict in both its arguments, and streamMap is strict in it second argument, so evaluating ruler even one step requires evaluating ruler one step which requires ...
The simplest solution is to make interleaveStreams lazy in its second argument, so that you don't need to evaluate ruler recursively until you've gotten at least one value from it.
interleaveStreams :: Stream a -> Stream a -> Stream a
interleaveStreams (Cons afirst arest) b =
let (Cons bfirst brest) = b
in Cons afirst (Cons bfirst (interleaveStreams arest brest))
Now
ruler == interleaveStreams (streamRepeat 0) (streamMap succ ruler)
== let (Cons bfirst brest) = streamMap succ ruler
in Cons 0 (Cons bfirst brest)
When we try to pattern match on ruler, we can get the first 0 without having to evaluate ruler further, which means when we do try to evaluate streamMap succ ruler, it can produce a first value (because we know that ruler starts with 0).
A simpler way to do this is to use a lazy pattern:
interleaveStreams :: Stream a -> Stream a -> Stream a
interleaveStreams (Cons afirst arest) ~(Cons bfirst brest) =
Cons afirst (Cons bfirst (interleaveStreams arest brest))
which desugars to the first example.
Another solution would be to hardcode the first element of ruler and reverse the arguments to interleaveStreams, i.e.,
ruler = Cons 0 $ interleaveStreams (streamMap succ ruler) (streamRepeat 0)
which makes ruler work but doesn't fix interleaveStreams in general.
So I have found that the built-in splitAt function in Haskell can be defined as follows:
splitAt :: Int -> [a] -> ([a], [a])
-- Pre: n >= 0
splitAt n []
= ([], [])
splitAt n (x : xs)
= if n == 0
then ([], x : xs)
else (x : xs', xs'')
where
(xs', xs'') = splitAt (n - 1) xs
What I don't understand here/can't get my head around is the where part.
As an example,
splitAt 2 "Haskell" should return (["Ha"],["skell"]), but I don't really understand how it works here to define (x:xs',xs'') as another function? How would this look like visually?
With the example:
splitAt 2 "Haskell"
= (('H':xs',xs''))
^ so this then does splitAt 1 "askell", but I'm very confused as to what happens to the xs',xs'' in the tuple above...
Thanks.
(xs', xs'') = splitAt (n - 1) xs
This takes the result of splitAt (n - 1) xs, which is a pair, and assigns the name xs' to the first element of that pair (i.e. the first n - 1 elements of xs) and xs'' to the second element (i.e. the remaining elements).
(x:xs', xs'')
This produces a pair. The first element of that pair is a list that's the result of prepending x to xs' (i.e. to the first n-1 elements of xs). The second element is xs'' (i.e. the remaining elements of xs).
From this Youtube video:
> let loeb fs = xs where xs = fmap ($ xs) fs
> loeb [length, (!! 0)]
[2,2]
The xs here is recursively defined, and how loeb terminates is beyond me.
try it:
loeb [length, (!! 0)]
= xs where xs = fmap ($ xs) [length, (!! 0)]
= xs where xs = [length xs, xs !! 0]
so of course length xs is just 2, and so the first element of xs (length xs) is 2 as well.
remember: length xs does not need to evaluate the items of the list:
length [undefined, undefined] = 2
The reason is that length does not evaluate the elements of the list. It simply counts the elements. length is (semantically equivalent) defined as:
length (_:xs) = 1 + length xs
length _ = 0
Even if one of the elements thus comes down on calculating an expression that results in an infinite loop, that doesn't matter. Al long as the list itself is not infinite of course.
Now of you call loeb [length, (!! 0)], it will be evaluated as:
loeb [length, (!! 0)]
xs = fmap ($ xs) [length,(!! 0)]
xs = [length xs,xs !! 0]
Thus the length xs performs lazy evaluation: it is not interested in the value of the elements, so they remain unsolved when counting.
Attempting to understand the differences between Clojure and Haskell. I have the following code which calculates the moving average of a time-series list of numbers:
movavg n [] = []
movavg n (x:xs) = map (/ n') sums
where
sums = scanl (+) (n' * x) $ zipWith (-) xs (replicate n x ++ xs)
n' = fromIntegral n
What would be the idiomatic version of this in Clojure?
I don't see why a very literal translation of this shouldn't be idiomatic, i.e.:
(defn movavg [n coll]
(when-let [[x & xs] (seq coll)]
(map #(/ % n)
(reductions + (* n x)
(map - xs (concat (repeat n x) xs))))))
Particularly code with a lot of sequence functions has always the potential to be very close to Haskell since they're lazy.
Edit: Shortened code according to Justin Kramer's suggestion.