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.
Related
Hi I'm quite new to haskell and just got into structural induction and was wondering if someone could explain the steps I should take it would be very helpful.
Question:
-- computes the sum of all numbers in the list
sum :: [Integer] -> Integer
sum [] = 0
sum (x:xs) = x + sum xs
-- appends two lists
(++) :: [Integer] -> [Integer] -> [Integer]
[] ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
Prove (by using structural induction) that the following equation holds, for all lists of integers xs and ys:
sum (xs ++ ys) = sum xs + sum ys
Don't forget to state the I.H. in the induction step. Please also make sure you clearly state the reasons why you make the steps in your proofs.
My steps:
To prove:
sum (xs ++ ys) = sum xs + sum ys
Proof: by structural induction
Let P ( ) <--- dont really know what to type in there so if someone could take it from there I would appreciete it greatly!
++ is defined by induction on its first argument, xs, so this is usually a good sign that we need to proceed by induction on xs.
Hence, we fix ys once for all, and define P(xs) as follows
P(xs) = (sum (xs ++ ys) == sum xs + sum ys)
Now you have to prove that P(xs) holds for all xs. Apply the induction principle on lists and you should be OK.
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, ...].
After reading this question: Functional proofs (Haskell)
And after looking at the inductive proof of forall xs ys. length (xs ++ ys) = length xs + length ys from the Haskell School of Music (page 164).
It seemed to me that function application distributes over list concatenation.
Hence the more general law might be that forall f xs ys. f (xs ++ ys) = f xs ++ f ys.
But how would one prove/disprove such a predicate?
-- EDIT --
I made a typo it was meant to be: forall f xs ys. f (xs ++ ys) = f xs + f ys, which matches what the previous question and the Haskell SoM uses. That being said, because of this typo, it's no longer "distributivity" property. However, #leftaroundabout made the correct answer for my original typoed question. And as for my intended question, the law is still not correct, because functions don't need the preserve the structural value. The f might give a completely different answer depending on the length of the list it is applied to.
No, this is clearly not true in general:
f [_] = []
f l = l
then
f ([1] ++ [2]) = f [1,2] = [1,2]
but
f [1] ++ f [2] = [] ++ [] = []
I'm sure the functions which do have this problem form an interesting class, but general functions can do pretty much anything to a list's structure which thwarts such invariants.
And after looking at the inductive proof of forall xs ys. length (xs ++ ys) = length xs + length ys from the Haskell School of Music (page 164).
It seemed to me that function application distributes over list concatenation.
Well, clearly that is not the case. For example:
reverse ([1..3] ++ [4..6]) /= reverse [1..3] ++ reverse [4..6]
The example that you're quoting is a special case that's called a monoid morphism: a function f :: m -> n such that:
m and n are monoids with binary operation <> and identity mempty;
f mempty = mempty
f (m <> m') == f m <> f m'
So length :: [a] -> Int is a monoid morphism, sending [] to 0 and ++ to +:
length [] = 0
length (xs ++ ys) = length xs + length ys
So I'm learning haskell right now, and I'm having trouble understanding what I'm doing wrong for the following function that emulates zip
1.ziplike xs ys = [(x,y)|c<-[0..(min (length xs) (length ys))-1],x<-xs!!c,y<-ys!!c]
2.ziplike xs ys = [(xs!!c,ys!!c)|c<-[0..(min (length xs) (length ys))-1]]
Now, I know that the correct answer is number 2, but I don't understand why number 1 is wrong for the call ziplike [1,2,3] ['a', 'b', 'c', 'd']. I THINK it's because it's trying to select the index for an individual char, but I'm not sure why.
The error is "Couldn't match expected type ‘[t1]’ with actual type ‘Char’"
To a first approximation:
If e::[a],
and x <- e appears to the right of the | in a list comprehension,
then x :: a wherever it is bound.
This leads to a bit of a problem in your case. You have ys :: [Char] and c :: Int, so that ys!!c :: Char. Hence:
We have ys!!c :: Char
and y <- ys!!c appears to the right of the | in a list comprehension,
so y :: ??? wherever it is bound.
But now we are stuck when trying to write the conclusion about what type y should have: Char is not a list of as, no matter what a we pick.
There are several possible fixes; one is to use let instead of <-, as in
ziplike xs ys = [(x,y)|c<-[0..min (length xs) (length ys)-1],let x=xs!!c; y=ys!!c]
It's a type error.
When you write "x from xs get-index c" (i.e. x <- xs !! c) the thing that you are getting "from" xs !! c is not necessarily a list. It's a technical detail, but it's important. The "from" arrow comes from monad syntax/do-notation. A list comprehension is actually just a do-expression specialized to the List monad; so the right hand side of an arrow <- needs to be a list in the List monad.
You can fix this, first off, by "cheating" with singleton lists, a la:
ziplike xs ys = [ (x,y) | c <- [0 .. min (length xs) (length ys) - 1],
x <- [xs !! c],
y <- [ys !! c]]
So these left-arrows are not "let" variable bindings, but they make Cartesian products: but the Cartesian product of n things with 1 thing with 1 thing is just n * 1 * 1 == n things. So this is great, if a little weird and possibly inefficient.
To do what you were trying to do (bind x and y inside of the list comprehension) you could also write something like:
ziplike xs ys = [let x = xs !! c; y = ys !! c in (x, y)
| c <- [0 .. min (length xs) (length ys) - 1]]
-- or --
ziplike xs ys = [(x, y)
| c <- [0 .. min (length xs) (length ys) - 1],
let x = xs !! c, let y = ys !! c]
-- or --
ziplike xs ys = [(x, y)
| c <- [0 .. min (length xs) (length ys) - 1],
let x = xs !! c; y = ys !! c]
Notice that these are all do-notation ideas tacked together with commas. Of course all of these look more clumsy than
ziplike xs ys = [(xs !! c, ys !! c) | c <- [0..min (length xs) (length ys) - 1]
which does the exact same thing.
With that said, all of this stuff is much more inefficient than the zip function's recursive character: if I double the size of the list, your implementations take 4 times as long to process the whole list; zip only takes twice as long. So be mindful of this "hidden O(n2) factor" in your programming.
I failed at reading RWH; and not one to quit, I ordered Haskell: The Craft of Functional Programming. Now I'm curious about these functional proofs on page 146. Specifically I'm trying to prove 8.5.1 sum (reverse xs) = sum xs. I can do some of the induction proof but then I get stuck..
HYP:
sum ( reverse xs ) = sum xs
BASE:
sum ( reverse [] ) = sum []
Left = sum ( [] ) (reverse.1)
= 0 (sum.1)
Right = 0 (sum.1)
INDUCTION:
sum ( reverse (x:xs) ) = sum (x:xs)
Left = sum ( reverse xs ++ [x] ) (reverse.2)
Right = sum (x:xs)
= x + sum xs (sum.2)
So now I'm just trying ot prove that Left sum ( reverse xs ++ [x] ) is equal to Right x + sum xs, but that isn't too far off from where I started sum ( reverse (x:xs) ) = sum (x:xs).
I'm not quite sure why this needs to be proved, it seems totally reasonable to use the symbolic proof of reverse x:y:z = z:y:x (by defn), and because + is commutative (arth) then reverse 1+2+3 = 3+2+1,
sum (reverse []) = sum [] -- def reverse
sum (reverse (x:xs)) = sum (reverse xs ++ [x]) -- def reverse
= sum (reverse xs) + sum [x] -- sum lemma below
= sum (reverse xs) + x -- def sum
= x + sum (reverse xs) -- commutativity assumption!
= x + sum xs -- inductive hypothesis
= sum (x:xs) -- definition of sum
However, there are underlying assumptions of associativity and commutativity that are not strictly warranted and this will not work properly for a number of numerical types such as Float and Double where those assumptions are violated.
Lemma: sum (xs ++ ys) == sum xs + sum ys given the associativity of (+)
Proof:
sum ([] ++ ys) = sum ys -- def (++)
= 0 + sum ys -- identity of addition
= sum [] ++ sum ys -- def sum
sum ((x:xs) ++ ys) = sum (x : (xs ++ ys)) -- def (++)
= x + sum (xs ++ ys) -- def sum
= x + (sum xs + sum ys) -- inductive hypothesis
= (x + sum xs) + sum ys -- associativity assumption!
= sum (x:xs) + sum ys -- def sum
Basically you need to show that
sum (reverse xs ++ [x]) = sum (reverse xs) + sum [x]
which then easily leads to
= x + sum (reverse xs)
= x + sum xs -- by inductive hyp.
The problem is to show that sum distributes over list concatenation.
Use the definition of a sum to break up (sum reverse xs ++[x]) into x + sum(reverse(xs)), and using your inductive hypothesis you know sum(reverse(xs)) = sum(xs). But I agree, induction is overkill for a problem like this.
Here's where I think you're stuck. You need to prove a lemma that says
sum (xs ++ ys) == sum xs + sum ys
To prove this law you will have to assume that addition is associative, which is true only for integers and rationals.
Then, you will also need to assume that addition is commutative, which is true for integers and rationals but also for floats.
Digression: The style of your proofs looks very strange to me. I think you will have an easier time writing these kinds of proofs if you use the style in Graham Hutton's book.