Call another function only once in a recursive function in Haskell - list

In Haskell, I have defined a recursive function. In this recursive function, I need to access the elements of a list.
This list is a list with different integers, which is created by another function. If I specify where lst = func_that_creates_list in this recursive function, the list gets created every time, which is very time consuming.
So somehow, I need to call this function that created this list only once and then use this list throughout the recursive function, but I don't now how to do this. Can anyone help me?
makeList :: Int -> [Integer]
makeList n = map (^2) [0..n]
recFunc :: Int -> [Integer]
recFunc 0 = 1
recFunc n = recFunc (n-1) + 2 * x!!n where n = makeList n

That's one instance of the common go-function idiom.
recFunc :: Int -> [Integer]
recFunc n = go n
where go 0 = 1
go n' = recFunc (n'-1) + 2 * x!!n'
x = makeList n
But as it is, this actually won't improve performance much because you're using the evil !! operator. Direct-indexing into a precomputed list is basically just as bad a computing it from scratch. Different story with vectors, but there's really no reason to use direct access here.
The proper way is to deconstruct the list as you go:
recFunc n = go n . reverse $ makeList n
where go n' (xω:x) = recFunc (n'-1) x + 2 * xω
go _ _ = 1
Actually the n' argument is unnecessary now
recFunc = go . reverse . makeList
where go (xω:x) = recFunc x + 2 * xω
go [] = 1
Still not optimal because you're carrying around a buildup of lazy thunks, better with a strict accumulator, that also makes the reverse unnecessary. (Well, it's anyway unnecessary in this example...)
recFunc = go 1 . makeList
where go acc (x₀:x) = acc `seq` go (2*x₀+acc) x
go acc [] = acc
But this function pattern is already implemented as foldl':
import Data.List
recFunc = foldl' (\acc x -> 2*x + acc) 1 . makeList
or simply
recFunc = (1+) . sum . map (2*) . makeList
Then you might of course also just inline makeList and fuse the map:
recFunc n = 1 + sum ((2*) . (^2) <$> [0..n])

You have a typo in the definition. Corrected, it is
makeList :: Int -> [Integer]
makeList n = map (^2) [0..n]
recFunc :: Int -> [Integer]
recFunc 0 = 1
recFunc n = recFunc (n-1) + 2 * xs!!n
where xs = makeList n
We can expand few more basic cases, taking care to rename variables so that all names are unique:
recFunc 0 = 1
recFunc 1 = recFunc 0 + 2 * xs1!!1
where xs1 = makeList 1
= 1 + 2 * xs1!!1
where xs1 = makeList 1
recFunc 2 = recFunc 1 + 2 * xs2!!2
where xs2 = makeList 2
= 1 + 2 * xs1!!1 + 2 * xs2!!2
where xs1 = makeList 1
xs2 = makeList 2
recFunc 3 = recFunc 2 + 2 * xs3!!3
where xs3 = makeList 3
= 1 + 2 * xs1!!1 + 2 * xs2!!2 + 2 * xs3!!3
where xs1 = makeList 1
xs2 = makeList 2
xs3 = makeList 3
-- ....
Indeed we see the problem you've indicated. But if we think about it for a moment, all the generated lists are the prefixes of the same list:
xs1 !! 1 == xs2 !! 1 == xs3 !! 1 == ....
and so we can re-write the above as
recFunc 0 = 1
recFunc 1 = 1 + 2 * xs3!!1
where xs3 = makeList 3
recFunc 2 = 1 + 2 * xs3!!1 + 2 * xs3!!2
where xs3 = makeList 3
recFunc 3 = 1 + 2 * xs3!!1 + 2 * xs3!!2 + 2 * xs3!!3
where xs3 = makeList 3
-- ....
and suddenly the problem goes away:
recFunc n = 1 + sum [ 2*xs!!i | i <- [1..n] ]
where xs = makeList n
Repeatedly scanning the list to sequential indices is a quadratic calculation, but the end result is we just access the list's elements in sequence, starting from the 2nd element in the list:
recFunc n = 1 + sum [ 2*x | x <- tail xs]
where xs = makeList n
= 1 + sum [ 2*x | x <- tail $ map (^2) [0..n]]
= 1 + sum [ 2*x | x <- map (^2) [1..n]]
= 1 + sum [ 2*x^2 | x <- [1..n]]
or, iteratively,
recFuncList = scanl (+) 1 . map (2*) .
scanl (+) 1 . iterate (+2) $ 3
= scanl (\acc x -> acc + 2*x) 1 .
scanl (\acc x -> acc + x) 1 . iterate (+2) $ 3
-- 3 5 7 9 11 13 15 17 19 21 ...
-- 1 4 9 16 25 36 49 64 81 100 121 ...
-- 1 3 11 29 61 111 183 281 409 571 771 1013 ...
= scanl (+) 1 . scanl (+) 2 . iterate (+4) $ 6
whichever you prefer.

Related

Concatenating list from a function to another recursive function in OCaml

So I am trying to code a relatively simple function in OCaml which takes an integer n and a list of integers up to 5 and then repeats all integers above 1 in said list n times.
I already have an existing function repeat which repeats whatever I feed it n times
let rec repeat : int -> 'a -> 'a list =
fun n a ->
match n with
| 0 -> []
| h -> a :: repeat (h-1) a ;;
Now here is the code for the function called Pentograph
let pentograph : int -> int list-> int list =
fun n letter ->
match letter with
|[] -> []
|h::t -> if h>1 then List.concat[(repeat n h);pentograph n t] else List.conca[h;pentograph n t];;
I get the following error:
Error: Unbound value pentograph
On trying to use the :: operator I get an error too as I can not use it to concat 2 lists.
Please help me figure out a solution to this problem!
EDIT: If the correct answer or more optimal answer uses map then please answer with that instead of trying to fix my code.
Lists in Ocaml are a variant type with some syntactic sugar vs. your typical user-defined variant type. A list is either an empty list ([]) or some element of type 'a tacked onto a list with the :: operator. As this is a recursive type, it's unsurprising that we use recursion to work on them.
Lists can also be concatenated with the # operator.
Your repeat function is good. I'm going to leave out the explicit types and reformat it a bit:
let rec repeat n a =
match n with
| 0 -> []
| _ -> a :: repeat (n - 1) a
You've defined an exit condition. If we ask the function to repeat something 0 times, we get an empty list. Otherwise we tack a onto the front of the result of repeating the function with one less repetition. This second stage sets up an update to the state which moves it closer to the exit condition.
repeat 4 6
6 :: repeat 3 6
6 :: 6 :: repeat 2 6
6 :: 6 :: 6 :: repeat 1 6
6 :: 6 :: 6 :: 6 :: repeat 0 6
[6; 6; 6; 6]
So, do the same thing with your pentograph function. It takes a number of time to repeat, and a list. We can recursively iterate through the list, so the natural exit condition is an empty list. If the list is empty, the result should be an empty list.
let rec pentograph n lst =
match lst with
| [] -> []
Otherwise the list will be some value and a remainder of the list.
let rec pentograph n lst =
match lst with
| [] -> []
| x::xs -> ...
Now we know that x is the first element of the list, so we can check if it is greater than 1.
let rec pentograph n lst =
match lst with
| [] -> []
| x::xs ->
if x > 1 then ...
else ...
If it's greater than 1, we'll farm out the repetition work to repeat and tack that onto the front of running pentograph on the rest of the list. If it's not, we'll just run the pentograph function on the rest of the list, ignoring x in our result.
let rec pentograph n lst =
match lst with
| [] -> []
| x::xs ->
if x > 1 then
repeat n x :: pentograph n xs
else
pentograph n xs
Now, let's try evaluating this for pentograph 2 [1; 2; 3].
pentograph 2 [1; 2; 3]
pentograph 2 [2; 3]
repeat 2 2 :: pentograph 2 [3]
repeat 2 2 :: repeat 2 3 :: pentograph 2 []
repeat 2 2 :: repeat 2 3 :: []
[2; 2] :: [3; 3] :: []
[[2; 2]; [3; 3]]
Now, the result you're probably looking for is [2; 2; 3; 3], so we can replaced list construction with list concatenation.
let rec pentograph n lst =
match lst with
| [] -> []
| x::xs ->
if x > 1 then
repeat n x # pentograph n xs
else
pentograph n xs
And now:
pentograph 2 [1; 2; 3]
pentograph 2 [2; 3]
repeat 2 2 # pentograph 2 [3]
repeat 2 2 # repeat 2 3 # pentograph 2 []
repeat 2 2 # repeat 2 3 # []
[2; 2] # [3; 3] # []
[2; 2; 3, 3]
Finally, as a stylistic preference, we can use guards on the patter matching, rather than if/else to clean it up a bit.
let rec pentograph n lst =
match lst with
| [] -> []
| x::xs when x > 1 -> repeat n x # pentograph n xs
| _::xs -> pentograph n xs

Adding 0-s to a list of until it's length is 8 in Haskell

So I have to make a decimal number into binary list like so: intToBitString 4 = [1,0,0].
Which i have done like so:
intToBitString n = reverse (helper n)
helper 0 = []
helper n
| n `mod` 2 == 1 = 1 : helper (n `div` 2)
| n `mod` 2 == 0 = 0 : helper(n `div` 2)
But then I also have to make a function called intToByte, which pads out the list with 0-s until it's length is 8 elements long. (so making it a bytestring) Like this:
intToByte 7 = [0, 0, 0, 0, 0, 1, 1, 1]
I have tried so many things, but they never work. I am a beginner, so I only know the "if" loop the way I showed above, and recursion, but I dont know anything fancy. One of my tries:
intToByte 0 = [0]
intToByte n
| eight n == helper2 n = reverse (helper2 n)
| otherwise = eight n
helper2 0 = []
helper2 n
| n `mod` 2 == 1 = 1 : helper2 (n `div` 2)
| n `mod` 2 == 0 = 0 : helper2 (n `div` 2)
eight n
| length (helper2 n) < 8 = 0 : eight n
| otherwise = helper2 n
I have been working on this for so many hours that i'm getting confused by it. But this is part of an important assignment, so help would be very appreciated!
First of all, you can simplify your code with:
helper2 :: Integral i => i -> [i]
helper2 0 = []
helper2 n = r : helper2 q
where (q,r) = quotRem n 2
Secondly, the above is a big endian representation [wiki]. Indeed, 7 is represented as [1,1,1], whereas 14 is for example represented as [0,1,1,1]. If we want to revers this, we can work with an accumulator:
helper2 :: Integral i => i -> [i]
helper2 = go []
where go rs 0 = rs
go rs n = go (r:rs) q
where (q,r) = quotRem n 2
This thus maps 7 to [1,1,1] and 14 to [1,1,1,0]. But now we still need to add leading zeros. We can do that for example by maintaing the number of elements already added to the list:
eight :: Integral i => i -> [i]
eight = go [] 0
where go rs l 0 = replicate (8-l) 0 ++ rs
go rs l n = go (r:rs) (l+1) q
where (q,r) = quotRem n 2
Padding can be as simple as computing how many additional elements to push to the list and then have those elements produced using the function replicate from the Prelude:
padLeft :: Int -> a -> [a] -> [a]
padLeft n x xs = replicate (n - length xs) x ++ xs
For instance:
> padLeft 8 0 [1, 1, 0]
[0,0,0,0,0,1,1,0]
One approach would be to define a function bits such that bits k converts its argument to a bit string of length k:
bits :: Int -> Int -> [Int]
bits 0 _n = []
bits k n | n < 0 = error "bits: negative"
| n > 2 * m - 1 = error "bits: overflow"
| otherwise = let (i, j) = n `divMod` m in i : bits (k - 1) j
where m = 2 ^ (k - 1)
Your function eight is then easily written as
eight :: Int -> [Int]
eight = bits 8
This gives:
> eight 4
[0,0,0,0,0,1,0,0]
> eight 7
[0,0,0,0,0,1,1,1]

How to Keep Non-Reduced Form of Ratio in Haskell

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
]

conversion from decimal to binary in SML

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]

What is the most idiomatic (or the fastest) way to sum up a list in OCaml?

Here is what I would implement
functional way
let sum l = List.fold_left (fun s x -> s+x) 0 l
imperative way
let sum l =
let sum = ref 0 in
List.iter (fun x -> sum := !sum +x) l;
!sum
Is there even a better/faster way to do it?
I asked this because the book Real World OCaml says:
# let sum list =
let sum = ref 0 in
List.iter list ~f:(fun x -> sum := !sum + x);
!sum
;;
val sum : int list -> int = <fun>
This isn't the most idiomatic (or the fastest) way to sum up a list, but it shows how you can use a ref in place of a mutable variable.
This is slightly cooler ;)
let sum l = List.fold_left (+) 0 l;;
To see performance:
open Printf
let sum1 l = List.fold_left (fun s x -> s+x) 0 l;;
let sum2 l = List.fold_left (+) 0 l;;
let sum3 = List.fold_left (+) 0;;
let rec make_list x acc = function
| 0 -> acc
| n -> make_list x (x :: acc) (n-1)
let l = make_list 1 [] 50000000;;
let _ = match Sys.argv.(1) with
| "1" -> printf "%d\n" (sum1 l)
| "2" -> printf "%d\n" (sum2 l)
| "3" -> printf "%d\n" (sum3 l)
| _ -> printf "Bad arg\n"
;;
Giving
$ ocamlc foo.ml
$ time ./a.out 1
50000000
real 0m8.204s
user 0m7.211s
sys 0m0.848s
$ time ./a.out 2
time ./a.out 3
50000000
real 0m8.226s
user 0m7.325s
sys 0m0.818s
$ 50000000
real 0m8.472s
user 0m7.561s
sys 0m0.837s
sum1 and sum2 have exactly the same bytecode:
branch L2
restart
L3: grab 1
acc 1
push
acc 1
addint
return 2
L1: acc 0
push
const 0
push
closure L3, 0
push
getglobal List!
getfield 14
appterm 3, 4
L2: closure L1, 0
push
acc 0
makeblock 1, 0
pop 1
setglobal Foo1!
sum3 has smaller bytecode but is slower
branch L2
restart
L1: grab 1
acc 1
push
acc 1
addint
return 2
L2: const 0
push
closure L1, 0
push
getglobal List!
getfield 14
apply 2
push
acc 0
makeblock 1, 0
pop 1
setglobal Foo3!
Anyone know why?
Using Batteries:
let sum = BatList.reduce (+)
(actually, Batteries already have BatList.sum function which does exactly what you want - so no need to write it :)
The alternative the author had in mind may have been to manually write the fold:
let low_level_sum list =
let rec loop sum = function
| [] -> sum
| x::xs -> loop (sum + x) xs in
loop 0 list
This is ugly and low level, and you should prefer List.fold_left (+) 0 unless you have a concrete performance concern. (And possibly even then - the OCaml compiler's inlining of recursive functions is being worked on and there may not be a performance advantage.)