I am trying to create a function rationalSumLowest that takes an Int n and returns a list of ratio numbers that sum to n, but only showing the ratio numbers that are already in reduced form. I have attempted to do this by creating the following functions:
mergeArrays :: [Int] -> [Int] -> [Ratio Int]
mergeArrays [] [] = []
mergeArrays (x:xs) (y:ys) = [x%y] ++ mergeArrays xs ys
rationalSum :: Int -> [Ratio Int]
rationalSum 0 = []
rationalSum 1 = []
rationalSum n = mergeArrays [1..(n-1)] [(n-1), (n-2)..1]
sumLowestBool :: Ratio Int -> Bool
sumLowestBool x
|(gcd (extractNumerator (x)) (extractDenominator (x)) == 1) = True
|otherwise = False
rationalSumLowest :: Int -> [Ratio Int]
rationalSumLowest 0 = []
rationalSumLowest 1 = []
rationalSumLowest n = [i | i <- rationalSum (n), sumLowestBool i == True]
It should run like this:
*Main> rationalSumLowest 5
[1 % 4,2 % 3,3 % 2,4 % 1]
*Main> rationalSumLowest 8
[1 % 7,3 % 5,5 % 3,7 % 1]
*Main> rationalSumLowest 12
[1 % 11,5 % 7,7 % 5,11 % 1]
With rationalSum running like this:
*Main> rationalSum 5
[1 % 4,2 % 3,3 % 2,4 % 1]
*Main> rationalSum 8
[1 % 7,1 % 3,3 % 5,1 % 1,5 % 3,3 % 1,7 % 1]
*Main> rationalSum 1
[]
My rationalSum function works properly, but my rationalSumLowest function does not. It returns the same list as the rationalSum function. I know this is because in Haskell, all ratios are automatically reduced and thus my sumLowestBool would return True for all entries in the list.
My question is: is there a way to keep the non-reduced form of the ratio in the original list so that my sumLowestBool function can work properly?
Since the ratios are reduced, checking that the gcd is 1 is the same as checking that the numerator hasn't changed.
import Data.Ratio
rationalSumLowest :: Integer -> [Rational]
rationalSumLowest n =
[ v
| i <- [1 .. n-1]
, let v = i % (n-i)
, numerator v == i
]
Related
Hi I have the following code:
let f n (xs) = if n < 0 then f (n-1) (n:xs) else xs
f (-3) [] !! 1
and I expect it to print -4
But it does not print anything and keeps calculation in background.
What is wrong with my code?
Let's step through the evaluation:
f (-3) []
f (-4) [-3]
f (-5) [-4, -3]
f (-6) [-5, -4, -3]
f (-7) [-6, -5, -4, -3]
...
Considering this, what do you expect f (-3) [] !! 1 to be? The value in the index 1 changes each iteration, so there's no way Haskell can know what it is until it reaches the non-recursive case at n >= 0, which never happens.
If you build the list in the other direction, it will work as you expect:
let f n = if n < 0 then n : f (n - 1) else []
> f (-3) !! 1
-4
So here's a pretend integer type:
data Int2 = ... -- 2 bit signed integers [-2, -1, 0, 1]
deriving (Num, Ord, Eq, ...)
Let's imagine that your function was defined on Int2 values:
f :: Int2 -> [Int2] -> [Int2]
f n (xs) = if n < 0 then f (n-1) (n:xs) else xs
This makes it fairly easy to work out what one evaluation step looks like for f n xs:
f 1 xs = xs
f 0 xs = xs
f (-1) xs = f (-2) (-1 : xs)
f (-2) xs = f 1 (-2 : xs) -- because finite signed arithmetic wraps around
and from there we can work out the full value of f n []:
f 1 [] = []
f 0 [] = []
f (-1) [] = f (-2) [-1] = f 1 [-2, -1] = [-2, -1]
f (-2) [] = f 1 [-2] = [-2]
Each computed a value, but note how it took 3 evaluation steps before we got a list out of f (-1) [].
Now see if you can work out how many steps it would take to compute f (-1) [] if it were defined on 4-bit numbers. 8-bit? 32-bit? 64-bit? What if it were using Integer which has no lower bound?
At no point does laziness help you because there's no partial result, only a recursive call. That's the difference between:
lazyReplicate 0 _ = []
lazyReplicate n x = x : lazyReplicate (n - 1) x
and
strictReplicate n x = helper [] n x where
helper xs 0 _ = xs
helper xs n x = helper (x : xs) n x
I am attempting to create a function in OCaml that gives the "k-average" of consecutive elements in a list. For example:
average 4 [1; 2; 3; 4; 5; 6] = [2; 3; 4]
since the average of 1, 2, 3, 4 is 2, of 2, 3, 4, 5 is 3, and of 3, 4, 5, 6 is 4.
I have created a function that averages the list, but with every 2 elements:
let rec average2 xs = match xs with
| [] -> []
| x :: [] -> [x]
| x :: x' :: xs -> if xs = [] then [(x + x') / 2] else [(x + x') / 2] #
(average2 (x'::xs))
How can I modify this to allow me to average k-elements?
What you should do is just verify that the list has the proper length and then two recursive functions will do it easily :
let average n l =
if List.length l < n then failwith "List is too small"
else
(* this function computes one k-average and returns the result *)
let rec aux2 acc i = function
| hd :: tl when i < n -> aux2 (acc + hd) (i + 1) tl
| _ -> acc / n
in
let rec aux acc l = match l with
(* the resulting list is reversed *)
| [] -> List.rev acc
| _ :: tl ->
(* Get the k-average of the k first elements of the list *)
let avgn = aux2 0 0 l in
(* if the rest of the list is too small, we reached the
end for sure, end *)
if List.length tl < n then List.rev (avgn :: acc)
(* recursive call on the rest of the list (without the head) *)
else aux (avgn :: acc) tl
in aux [] l
I need a function that checks a condition on a list.
For example:
countP :: [a] -> (a -> Bool) -> Int
with the input:
countP [1,-2,0,-1,5] (>0)
should return 2, because there are two numbers greater than zero.
Here's what i've done so far:
countP :: [a] -> (a -> Bool) -> Int
countP [] _ = []
countP (x:xs) condition = if condition x then 1:countP xs condition else countP xs condition
It's returning [1,1] instead of the number two. It must be recursive.
How can i do this ?
You have to add the result, like this
countP :: [a] -> (a -> Bool) -> Int
countP [] _ = 0
countP (x:xs) condition = (if condition x then 1 else 0) + (countP xs condition)
Whenever condition x evaluates to True, we use 1 otherwise 0 and we recursively call countP and add them.
So, when you invoke it like this
countP [1, -2, 0, -1, 5] (>0)
it will be evaluated recursively, like this
(if (> 0) 1 then 1 else 0) + (countP [-2, 0, -1, 5] (> 0))
1 + (countP [-2, 0, -1, 5] (> 0))
1 + (if (> 0) -1 then 1 else 0) + (countP [0, -1, 5] (> 0))
1 + 0 + (countP [0, -1, 5] (> 0))
1 + 0 + 0 + (countP [-1, 5] (> 0))
1 + 0 + 0 + 0 + (countP [5] (> 0))
1 + 0 + 0 + 0 + 1 + (countP [] (> 0))
1 + 0 + 0 + 0 + 1 + 0 = 2
(countP [] (> 0)) is evaluated to be 0 because of our base condition of our recursive function countP [] _ = 0. It means that no matter what the second parameter is, if the first parameter is an empty list, then return 0.
You seem to be over thinking this. You can use some of the Prelude provided functions and compose them to produce the result:
length $ filter (>0) [1,-2,0,-1,5]
length will take a list and tell you how long it is.
filter takes a predicate and tells you how many elements in a provided list match that predicate.
So if you get the length of the filtered list, you are set.
countP xs f = length $ filter f xs
There is a function specifically for counting the number of things in a list, and it's called length. You could do something like
countP' [] _ = []
countP' (x:xs) condition = if condition x then 1 : countP' xs condition else countP' xs condition
countP xs condition = length (countP' xs condition)
However, this takes two functions and it does extra work. Instead you could work directly with Ints instead of [Int]s:
countP :: [a] -> (a -> Bool) -> Int
countP [] _ = 0
countP (x:xs) condition = ...
I'll still let you fill in the blanks here, know that you are not very far from the correct solution with what you already have.
However, if I were going to implement this code in a project, I would simply reach for length and filter:
countP xs condition = length (filter condition xs)
This is what I would call the idiomatic definition (up to argument order).
I have the following formula
fun foo 0 = [0]
| foo num = let val l = (num mod 2)::foo(num div 2) in
rev l
end;
which is supposed to convert from decimal to binary.It has the following signature
val foo = fn : int -> int list
I am not sure where exactly I am getting things wrong as I am getting incorrect results.May someone help me figure out where I am making the error?
The problem seems to be that you reverse the resulting list in every recursive step, instead of just once at the end.
Also, you probably need to map 0 to the empty list, otherwise you'll have one 0 too many in the end.
Exactly what Andreas said. Now, the obvious way to get around this is to use a wrapper function:
fun f n =
let
fun f' 0 = []
| f' num = num mod 2 :: f' (num div 2)
in
rev (f' n)
end
This works, but has the disadvantage of first building up the list, and then traversing it (the rev call). It also isn't tail-recursive. We can do better!
Instead of using reverse, we flip things around and use an accumulator:
fun g n =
let
fun g' 0 acc = acc
| g' num acc = g' (num div 2) (num mod 2 :: acc)
in
g' n []
end
To understand the difference, let's see what happens if we run each of these on the number 4.
f 4 -> rev (f' 4)
-> rev (4 mod 2 :: f' (4 div 2))
-> rev (0 :: f' 2)
-> rev (0 :: 2 mod 2 :: f' (2 div 2))
-> rev (0 :: 0 :: f' 1)
-> rev (0 :: 0 :: 1 mod 2 :: f' (1 div 2))
-> rev (0 :: 0 :: 1 :: f' 0)
-> rev (0 :: 0 :: 1 :: [])
-> [1, 0, 0]
g 4 -> g' 4 []
-> g' (4 div 2) (4 mod 2 :: [])
-> g' 2 (0 :: [])
-> g' (2 div 2) (2 mod 2 :: 0 :: [])
-> g' 1 (0 :: 0 :: [])
-> g' (1 div 2) (1 mod 2 :: 0 :: 0 :: [])
-> g' 0 (1 :: 0 :: 0 :: [])
-> [1, 0, 0]
I have been messing with some Haskell functions, some I have understand and some don't.
For example if we do: scanl (+) 0 [1..3] my understanding is the following:
1. the accumulator is 0 acc = 0 |
2. (+) applied to acc and first el acc = 0 + 1 = 1 |
3. (+) applied to latest acc and snd el acc = 1 + 2 = 3 |
4. (+) applied to latest acc and third acc = 3 + 3 = 6 V
Now when we make the list we get [0, 1, 3, 6].
But I can't seem to understand how does scanr (+) 0 [1..3] gives me: [6,5,3,0]
Maybe scanr works the following way?
1. the first element in the list is the sum of all other + acc
2. the second element is the sum from right to left (<-) of the last 2 elements
3. the third element is the sum of first 2...
I don't see if that's the pattern or not.
scanr is to foldr what scanl is to foldl. foldr works from the right:
foldr (+) 0 [1,2,3] =
(1 + (2 + (3 + 0))) =
(1 + (2 + 3)) =
(1 + 5) =
6
-- [ 6, 5, 3, 0 ]
and scanr just shows the interim results in sequence: [6,5,3,0]. It could be defined as
scanr (+) z xs = foldr g [z] xs
where
g x ys#(y:_) = x+y : ys
scanl though should work like
scanl (+) 0 [1,2,3] =
0 : scanl (+) (0+1) [2,3] =
0 : 1 : scanl (+) (1+2) [3] =
0 : 1 : 3 : scanl (+) (3+3) [] =
0 : 1 : 3 : [6]
so it must be that
scanl (+) z xs = foldr f h xs z
where h z = [z]
f x ys z = z : ys (z + x)
scanl and scanr are used to show the value of the accumulator on each iteration. scanl iterates from left-to-right, and scanr from right-to-left.
Consider the following example:
scanl (+) 0 [1, 2, 3]
-- 0. `scanl` stores 0 as the accumulator and in the output list [0]
-- 1. `scanl` adds 0 and 1 and stores 1 as the accumulator and in the output list [0, 1]
-- 2. `scanl` adds 1 and 2 and stores 3 as the accumulator and in the output list [0, 1, 3]
-- 3. `scanl` adds 3 and 3 and stores 6 as the accumulator and in the output list [0, 1, 3, 6]
-- 4. `scanl` returns the output list [0, 1, 3, 6]
As you can see, scanl stores the results of the accumulator while it's iterating through the list. This is the same for scanr, but the list is iterated in reverse.
Here's another example:
scanl (flip (:)) [] [1, 2, 3]
-- [[], [1], [2,1], [3,2,1]]
scanr (:) [] [1, 2, 3]
-- [[1,2,3], [2,3], [3], []]