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]
Related
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
I am trying to run the following code on a coding question website and it says there is a runtime error, but running it on the top-level ocaml seems to work fine. Could there be any source of error in the code? Thanks in advance
The question is to find the number of 'good segments' within the given list and a specific number. A good segment is defined as follows:
A and B are positive integers such that A < B.
x that satisfies A <= x <= B is not an element of the given list.
The following are the inputs.
n, which is the number of elements in the list that will be given.
a, b, c, ... which are the elements of the list.
t, which is the number that must be included in the segment.
The output should be a single number printed out.
Edited Code:
let rec drop_value l to_drop =
match l with
| [] -> []
| hd :: tl ->
let new_tl = drop_value tl to_drop in
if hd = to_drop then new_tl else hd :: new_tl
;;
let rec find_start li t cur_min =
match li with
| [] -> cur_min
| hd :: tl -> let new_min = abs (t - hd) in
if new_min = 0 then find_start tl t new_min
else if new_min < cur_min && t > hd then find_start tl t new_min
else find_start tl t cur_min
;;
let rec find_end li t cur_min =
match li with
| [] -> cur_min
| hd :: tl -> let new_min = abs (t - hd) in
if new_min = 0 then find_end tl t new_min
else if new_min < cur_min && t < hd then find_end tl t new_min
else find_end tl t cur_min
;;
let rec contains_value l value =
match l with
| [] -> false
| hd :: tl -> if hd = value then true else contains_value tl value
;;
let nums = ref [];;
let n = read_int () in
for i = 1 to n do
Scanf.scanf " %d" (fun a ->
nums := a :: !nums)
done;
Scanf.scanf " %d" (fun t ->
if contains_value !nums t then print_int 0
else let start = if List.length !nums = 1 then 1 else abs (find_start !nums t 1001 - t) in
let finish = find_end (drop_value !nums start) t 1001 + t in
if t > start && t < finish then (if start = 1 && List.length ! nums = 1 then print_int ((t - start + 1) * (finish - t) - 1) else print_int ((t - start) * (finish - t) - 1))
else let start = 1 in print_int ((t - start + 1) * (finish - t) - 1))
;;
eg.
5
4 8 13 24 30
10
should give
5
=> [9, 10], [9, 11], [9, 12], [10, 11], [10, 12]
You don't describe the exact input format that your code is going to get. This makes it pretty much impossible to debug your code.
When I compile and run your code (as m.ml) using the input you describe I see this:
$ ./m
5 4 8 13 24 30 10
Fatal error: exception Failure("int_of_string")
In fact no matter what format I try for the input I get the same result.
So that is probably what is happening at the website.
In my experience it always causes more harm than good to use scanf. Combining it with other input functions is probably going to make things worse.
If you describe the expected format of the input carefully, somebody on StackOverflow can recommend a way to get your numbers.
In the meantime here's a way to read all the numbers on one line:
let rec split_at list n =
if n = 0 then
([], list)
else
match list with
| [] -> ([], [])
| h :: t ->
let (a, b) = split_at t (n - 1) in (h :: a, b)
in
let (nums, t) =
let line = read_line () in
let nstrs = Str.split (Str.regexp "[ \t][ \t]*") line in
match List.map int_of_string nstrs with
| [] -> failwith "no numbers"
| n :: rest ->
if List.length rest <> n + 1 then
failwith "bad count"
else
let (nums, tlist) = split_at rest n in
(nums, List.hd tlist)
in
. . .
I'm a newbie in haskell!
I need to write a function that process an ID number. I need to check the first digit of the integer number. If the number is 1 or 3 then the client is male, if the number is 2 or 4 then female. I think I need a helper function which splitting the long integer number to an integer list.
The fuction called szemelyinem, it has one parameter/argument which is a 11 long integer number.
This is the spliting function:
split :: Integral x => x -> [x]
split 0 = []
split x = split (x `div` 10) ++ [x `mod` 10]
In my head the notion is Split the long number then load it to the function, then check the first element in the list and return with one string. But I don't know how to start this :/
I have an example like this:
szemelyinem 40504291247
Result: "female"
This is the first step.
split :: Integral x => x -> [x]
split 0 = []
split x = split (x `div` 10) ++ [x `mod` 10]
This is the second.
rev:: [Integer] -> [Integer]
rev [] = []
rev (h:t) = rev t ++ [h]
This is the third step
nemdel :: [Integer] -> [Integer]
nemdel [] = []
nemdel (h:t) = drop 10 (h:t)
This is the fourth.
listtonumb:: [Integer] -> Integer
listtonumb = foldl addDigit 0
where addDigit num d = 10*num + d
And the last one.
szemelyinem :: Integer -> [Char]
szemelyinem szam =
if listtonumb(nemdel(rev(split szam))) == 1 || listtonumb(nemdel(rev(split szam))) == 3
then "male"
else if listtonumb(nemdel(rev(split szam))) == 2 || listtonumb(nemdel(rev(split szam))) == 4
then "Female"
else error "Bad ID"
I'm sure about that is a complex way to do this shit.
I am learning Haskell and am currently creating a program that finds all common divisors from 3 different Int:s.
I have a working program but the evaluation time is very long on big numbers. I want advice on how to optimize it.
EXAMPLE: combineDivisors 234944 246744 144456 == [1,2,4,8]
As said I am very new to this so any help is appreciated.
import Data.List
combineDivisors :: Int -> Int -> Int -> [Int]
combineDivisors n1 n2 n3 =
mergeSort list
where list = getTrips concList
concList = isDivisor n1 ++ isDivisor n2 ++ isDivisor n3
isDivisor n = [x | x <- [1..n], mod n x == 0]
getTriplets :: Ord a => [a] -> [a]
getTriplets = map head . filter (\l -> length l > 2) . group . sort
--Merge sort--
split :: [a] -> ([a],[a])
split xs =
let
l = length xs `div` 2
in
(take l xs, drop l xs)
merge :: [Int] -> [Int] -> [Int]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| y < x = y : merge (x:xs) ys
| otherwise = x : merge xs (y:ys)
mergeSort :: [Int] -> [Int]
mergeSort [] = []
mergeSort [x] = [x]
mergeSort xs =
let
(xs1,xs2) = split xs
in
merge (mergeSort xs1) (mergeSort xs2)
If you don't care too much about memory usage, you can just use Data.IntSet and a function to find all factors given a number to do this.
First, let's make a function that returns an IntSet of all factors of a number-
import qualified Data.IntSet as IntSet
factors :: Int -> IntSet.IntSet
factors n = IntSet.fromList . f $ 1 -- Convert the list of factors into a set
where
-- Actual function that returns the list of factors
f :: Int -> [Int]
f i
-- Exit when i has surpassed square root of n
| i * i > n = []
| otherwise = if n `mod` i == 0
-- n is divisible by i - add i and n / i to the list
then i : n `div` i : f (i + 1)
-- n is not divisible by i - continue to the next
else f (i + 1)
Now, once you have the IntSet corresponding to each number, you just have to do a intersection on them to get the result
commonFactors :: Int -> Int -> Int -> [Int]
commonFactors n1 n2 n3 = IntSet.toList $ IntSet.intersection (factors n3) $ IntSet.intersection (factors n1) $ factors n2
That works but is a bit ugly. How about making an intersections function that can take multiple IntSets and produce a final intersection result.
intersections :: [IntSet.IntSet] -> IntSet.IntSet
intersections [] = IntSet.empty
intersections (t:ts) = foldl IntSet.intersection t ts
That should fold on a list of IntSets to find the final intersection
Now you can refactor commonFactors to-
commonFactors :: Int -> Int -> Int -> [Int]
commonFactors n1 n2 n3 = IntSet.toList . intersections $ [factors n1, factors n2, factors n3]
Better? I'd think so. How about one last improvement, a general commonFactors function for n amount of ints
commonFactors :: [Int] -> [Int]
commonFactors = IntSet.toList . intersections . map factors
Note that this is using an IntSet, so it is naturally limited to Ints. If you want to use Integer instead - just replace IntSet with a regular Set Integer
Output
> commonFactors [234944, 246744, 144456]
[1,2,4,8]
You should use the standard algorithm where you prime factorize their GCD:
import Data.List
import qualified Data.Map.Strict as M
-- infinite list of primes
primes :: [Integer]
primes = 2:3:filter
(\n -> not $ any
(\p -> n `mod` p == 0)
(takeWhile (\p -> p * p <= n) primes))
[5,7..]
-- prime factorizing a number
primeFactorize :: Integer -> [Integer]
primeFactorize n
| n <= 1 = []
-- we search up to the square root to find a prime factor
-- if we find one then add it to the list, divide and recurse
| Just p <- find
(\p -> n `mod` p == 0)
(takeWhile (\p -> p * p <= n) primes) = p:primeFactorize (n `div` p)
-- if we don't then the number has to be prime so we're done
| otherwise = [n]
-- count the number of each element in a list
-- e.g.
-- getCounts [1, 2, 2, 3, 4] == fromList [(1, 1), (2, 2), (3, 1), (4, 1)]
getCounts :: (Ord a) => [a] -> M.Map a Int
getCounts [] = M.empty
getCounts (x:xs) = M.insertWith (const (+1)) x 1 m
where m = getCounts xs
-- get all possible combinations from a map of counts
-- e.g. getCombos (M.fromList [('a', 2), ('b', 1), ('c', 2)])
-- == ["","c","cc","b","bc","bcc","a","ac","acc","ab","abc","abcc","aa","aac","aacc","aab","aabc","aabcc"]
getCombos :: M.Map a Int -> [[a]]
getCombos m = allFactors
where
list = M.toList m
factors = fst <$> list
counts = snd <$> list
possible = (\n -> [0..n]) <$> counts
allCounts = sequence possible
allFactors = (\count -> concat $ zipWith replicate count factors) <$> allCounts
-- get the common factors of a list of numbers
commonFactorsList :: [Integer] -> [Integer]
commonFactorsList [] = []
commonFactorsList l = sort factors
where
totalGcd = foldl1 gcd l
-- then get the combinations them and take their products to get the factor
factors = map product . getCombos . getCounts . primeFactorize $ totalGcd
-- helper function for 3 numbers
commonFactors3 :: Integer -> Integer -> Integer -> [Integer]
commonFactors3 a b c = commonFactorsList [a, b, c]
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