OCaml Syntax Error at the end of nested loops - ocaml
I'm trying to create a function that calculates the odds of a team winning a tournament based on the rules here. I already have a python implementation here, but I wanted to try and do it in OCaml, a language that is very new to me. I'm running into issues with syntax errors, and it's not clear to me why I'm getting the errors. I also know that, because I'm "translating" the code from python, it is not optimal for OCaml, so if there better "OCaml ways" of doing the things I'm trying to do, I'd like to hear that feedback as well.
open Format
open List
let tourney = [1;16;8;9;5;12;4;13;6;11;3;14;7;10;2;15];;
let odds x =
function y -> if x > y then 1.0-.(x/.x+.y) else y/.(x+.y);;
let replace l pos a = List.mapi (fun i x -> if i = pos then a else x) l;;
let rec index l a =
match l with
| [] -> -1
| x::xs -> if x != a then 1 + index xs a else 0;;
let seed_odds L seed =
let team_ind = index tourney seed
and rounds = [2;4;8;16]
and round_odds = [] ;
for i = 1 to length rounds do
let temp = [] in
for j = 1 to length tourney do
0.0 :: temp;
done;
temp :: round_odds;
done;
for r = 0 to (length rounds)-1 do
let groups = (length tourney) / (nth rounds r);
for i = 0 to groups do
let teams = slice tourney i*(nth rounds r) (i+1)*(nth rounds r);
for t = 0 to (length teams) do
let odds_to_advance = ref 0.0;
let teams_ =
if t < ((length teams) / 2) then slice teams ((length teams)/2) (length teams)-1 else slice teams 0 ((length teams)/2)-1 ;
for t_ = 0 to length teams_ do
if nth teams t != nth teams_ t_ then
begin
if (nth rounds r) = 2 then
begin
odds_to_advance := odds_to_advance +. odds (nth teams t) (nth teams_ t_);
end
else
begin
odds_to_advance := odds_to_advance +. (odds (nth teams t) (nth teams_ t_)) *. (nth (nth round_odds r-1 ) (index tourney (nth teams_ t_) )) ;
end
end
else ()
done;
if nths rounds r > 2 then
begin
odds_to_advance := odds_to_advance *. (nth (nth round_odds r-1 ) (index tourney (nth teams t) )) ;
end
else ()
(*replace (nth round_odds r) (i * (nth rounds r) + t) odds_to_advance ;*)
done;
done;
done;
Ok, the answers to my previous issues make sense, thank you! I've updated the code and cleaned things up:
open Format
open Array
open List
let tourney = [1.;16.;8.;9.;5.;12.;4.;13.;6.;11.;3.;14.;7.;10.;2.;15.];;
let odds x =
function y -> if x > y then 1.0-.(x/.x+.y) else y/.(x+.y);;
printf "The odds are %f" (odds 2. 15.);;
let replace l pos a = List.mapi (fun i x -> if i = pos then a else x) l;;
let rec index l a =
match l with
| [] -> -1
| x::xs -> if x != a then 1 + index xs a else 0;;
let rec fold_until f acc n = function
| [] -> (acc, [])
| h :: t as l -> if n = 0 then (acc, l)
else fold_until f (f acc h) (n - 1) t
let slice list i k =
let _, list = fold_until (fun _ _ -> []) [] i list in
let taken, _ = fold_until (fun acc h -> h :: acc) [] (k - i + 1) list in
List.rev taken;;
let seed_odds l seed =
let team_ind = index tourney seed
and rounds = [2;4;8;16]
and round_odds = make_matrix 4 16 0.0 in
for r = 0 to (length rounds)-1 do
let groups = (length tourney) / (nth rounds r) in
for i = 0 to groups-1 do
let teams = slice tourney (i*(nth rounds r)) ((i+1)*(nth rounds r)) in
for t = 0 to (length teams)-1 do
let odds_to_advance = ref 0.0 in
let teams_ =
if t < ((length teams) / 2) then slice teams ((length teams)/2) ((length teams)-1) else slice teams 0 (((length teams)/2)-1) in
for t_ = 0 to (length teams_)-1 do
if nth teams t != nth teams_ t_ then
begin
if (nth rounds r) = 2 then
begin
let od = odds (nth teams t) (nth teams_ t_) in
odds_to_advance := !odds_to_advance +. od
end
else
begin
let od = odds (nth teams t) (nth teams_ t_)
and prev = round_odds.(r-1).(index tourney (nth teams_ t_) ) in
odds_to_advance := !odds_to_advance +. od *. prev
end
end
else ()
done
if (nth rounds r) > 2 then
begin
let prev = round_odds.(r-1).(index tourney (nth teams t)) in
odds_to_advance := !odds_to_advance *. prev
end
else()
round_odds.(r).((i*(nth rounds r))+t) <- !odds_to_advance
done
done
done
round_odds.(3).(team_ind);;
printf "The odds of two winning right now are %f" (seed_odds tourney 2.);;
The only error I get now is:
66 | if (nth rounds r) > 2 then
^^
Error: Syntax error
Not sure what the issue is now, because I've checked over the let statements, made sure begin/ends were closed, etc.
The first thing I see is that you have quite a few instances of let with no matching in.
At the top level of a module you can have let name = value. This declares a value to be exported from the module (roughly speaking).
Everywhere else (inside function definitions in particular), every let has to have a matching in. The let expression looks like this:
let v = expr1 in expr2
It declares a local variable v with the value expr1. The scope of this local variable is expr2. The in expr2 part is not optional.
Here are the lines where you have let with no matching in:
let team_ind = index tourney seed
let groups = (length tourney) / (nth rounds r);
let teams = slice tourney i*(nth rounds r) (i+1)*(nth rounds r);
let odds_to_advance = ref 0.0;
let teams_ =
All of these are syntax errors. In general you can fix them by adding in and removing a semicolon if you have one.
As a side comment, in OCaml semicolons are used to separate expressions that should be evaluated sequentially. The semicolon is not a statement terminator (as in languages influenced by C). It's a separator, similar in many ways to an operator.
Update
As another side comment, once you get your code working you might want to look for ways to make it more idiomatic OCaml. For example, using List.nth is almost always bad practice because it takes linear time to reach the nth element of a list. OCaml is not like some other languages where what they call lists are actually arrays (randomly accessible in constant time). OCaml lists are really lists (as in Lisp and other FP languages).
Related
How to count the number of successive duplicates in Ocaml
I'm trying to write a function that takes in a list, and returns the number of successive duplicate elements in the list. For example, given [1;2;3;3;4;4;5], the function should return 2 This is my initial implementation, but unfortunately it always returns 0. I'm not quite sure where the bug lies. Any help on how to improve it will be highly appreciated. let rec count_successive_duplicates (lst: int list) (count: int) : (int) = match lst with | [] | [_]-> 0 | x :: y :: tl -> if x = y then count_successive_duplicates (y::tl) (count + 1) else count_successive_duplicates (y::tl) count ;; let () = print_int (count_successive_duplicates [1;2;3;3;4;4;5] 0)
In the end, you'll want to return the accumulator with the count instead of 0 always: let rec count_successive_duplicates (lst: int list) (count: int) : (int) = match lst with | [] | [_] -> count (* ^^^^^ */) | x :: y :: tl -> count_successive_duplicates (y::tl) (count + if x = y then 1 else 0)
Seems I was doing something silly by always returning 0 for the base case, instead of the computed count. The previous version was just ignoring the computed count it received. This now works: let rec count_successive_duplicates lst count : (int) = match lst with | [] | [_]-> count | x :: y :: tl -> if x = y then count_successive_duplicates (y::tl) (count + 1) else count_successive_duplicates (y::tl) count ;; let () = print_int (count_successive_duplicates [1;2;3;3;4;4;5] 0)
How to use list comprenhension in Ocaml
This code is in Haskell. How can i do the same thing in OCAML? perfect n = [x | x<-[1..n], sum(f x) == x] f x = [i | i<-[1..x-1], x `mod` i ==0]
While Jeffrey's answer is correct, using appropriate libraries (in this case, sequence), you can get something that is similar in terseness and semantics to the Haskell style: module S = Sequence let sum = S.fold (+) 0 let f x = S.filter (fun i -> x mod i = 0) S.(1 -- (x-1)) let perfect n = S.filter (fun x -> sum (f x) = x) S.(1 -- n)
You're using many (really nice) features of Haskell that don't exist in OCaml. For list comprehensions, you can use List.filter. For the notation [x .. y] you can use this range function: let range a b = let rec go accum i = if i > b then List.rev accum else go (i :: accum) (i + 1) in go [] a For sum you can use this: let sum = List.fold_left (+) 0
Splitting a list using an index
I have a list of integers named t that has an even length n = List.length t. I want to get two lists, the partition of t from index 0 to (n / 2 - 1), and the partition of t from index (n / 2) to (n-1). In other words, I want to split the list t in two parts, but I cannot find anything that does that in the List module (there is List.filter, but it does not filter by index, it takes a function instead). An example of what I want to do: let t = [8 ; 66 ; 4 ; 1 ; -2 ; 6 ; 4 ; 1] in (* Split it to get t1 = [ 8 ; 66 ; 4 ; 1] and t2 = [-2 ; 6 ; 4 ; 1] *) For now,I have something like this let rec split t1 t2 n = match t1 with | hd :: tl when (List.length tl > n) -> split tl (hd :: t2) n; | hd :: tl when (List.length tl = n) -> (t1,t2); | _ -> raise (Failure "Unexpected error");; let a = [1;2;3;4;7;8];; let b,c = split a [] (List.length a / 2 - 1);; List.iter (fun x -> print_int x) b; print_char '|'; List.iter (fun x -> print_int x) c; Output is: 478|321, the order has been reversed!
Calculating the length of the list requires walking the list, so it takes time that's linear in the length of the list. Your attempt calculates the length of the remaining list at each step, which makes the total running time quadratic. But you actually don't need to do that! First you calculate the total length of the list. After that, the place to cut is halfway from the beginning, which you can locate by incrementing a counter as you go through the list. As for the reversal, let's look at what happens to the first element of the list. In the first call to split, the accumulator t2 is the empty list, so h gets put at the end of the list. The next element will be placed before that, and so on. You need to put the first element at the head of the list, so prepend it to the list built by the recursive call. let rec split_at1 n l = if n = 0 then ([], l) else match l with | [] -> ([], []) (*or raise an exception, as you wish*) | h :: t -> let (l1, l2) = split_at1 (n-1) t in (h :: l1, l2);; let split_half1 l = split_at1 (List.length l / 2) l;; This operates in linear time. A potential downside of this implementation is that the recursive call it makes is not a tail call, so it will consume a large amount of stack on large lists. You can fix this by building the first half as an accumulator that's passed to the function. As we saw above, this creates a list in reverse order. So reverse it at the end. This is a common idiom when working with lists. let rec split_at2 n acc l = if n = 0 then (List.rev acc, l) else match l with | [] -> (List.rev acc, []) | h :: t -> split_at2 (n-1) (h :: acc) t;; let split_half2 l = split_at2 (List.length l / 2) [] l;;
Generate all list of a given length between two values (OCaml or other languages)
I am new to ocaml and trying to write some code to generate all lists of number between two value. For example, if I call this function generate, I want to obtain something like this : let generate ~min ~max ~length (* Maybe other arguments *) = (* The code *) ;; generate ~min:0 ~max:3 ~length:4;; Should return [ [0;0;0]; [1;0;0]; [2;0;0]; [3;0;0]; [0;1;0]; And so on, to [3;2;3]; [0;3;3]; [1;3;3]; [2;3;3]; [3;3;3]; ] I already tried code like this : open Core.Std;; type next_list = | Complete of int list | Partial of int list | Result of (int array) list ;; let rec next ~r ~min ~max ~l = let detox = function | Partial a -> a | _ -> assert false in match l with | Partial (hd :: tl) when hd <= max -> Partial (hd + 1 :: tl) | Partial (hd :: tl) when hd = max + 1 -> next ~r ~min ~max ~l:(Partial (min :: (detox (next ~r ~min ~max ~l:(Partial tl))) )) | Complete (hd :: tl) when hd <= max -> next ~r:([l] :: r) ~min ~max ~l:(Complete (hd + 1 :: tl)) | Complete (hd :: tl) when hd = max + 1 -> next ~r ~min ~max ~l:(Complete (min :: (detox (next ~r ~min ~max ~l:(Partial tl))))) (*| Partial [] -> next ~r ~min ~max ~l:(Result r)*) | Result a -> Result a It may be spread around several functions if necessary, that is not a problem. I am also interested by non ocaml code or idea. Thanks for your help. This is my first question on Stackoverflow, do not hesitate to say if my question is unclear.
here some solution : First, let's define that takes 2 lists l1 & l2 as input and that produces a list of list, where each element is l2 augmented by 1 element of l1 : let enumerate l ll = List.fold ~init:[] ~f:(fun op x -> (x::ll)::op) l;; enumerate [0;1;2;3] [4;5;6];; - : int list list = [[3; 4; 5; 6]; [2; 4; 5; 6]; [1; 4; 5; 6]; [0; 4; 5; 6]] Now generate : let rec generate length ll = if length=1 then List.fold ~init:[] ~f:(fun op x -> [x]::op) ll else let result = generate (length-1) ll in List.fold ~init:[] ~f:(fun op x -> (enumerate ll x)#op) result;; and usage is as follows : generate 2 [1;2;3];; (* instead of generate ~min:1 ~max:3 ~length:2 *) Some explanation : List.fold ~init:[] ~f:(fun op x -> [x]::op) ll => this creates the initial list of list (singleton) And the second : takes each of the list of length -1 and performs the enumeration.
Here's a hint: let count_prefix low high lists = ??? let generate min max length = let rec recur low high len = if len = 0 then [] else count_prefix low high (recur low high (len - 1)) in recur min max length count_prefix should return a list that is the elements of lists prefixed with the numbers low to high. If lists is empty, it should return a list of lists containing the numbers low to high. That is: count_prefix 0 3 [] => [[0]; [1]; [2]] count_prefix 0 3 [[10];[20]] => [[0; 10]; [0; 20]; [1; 10]; [1; 20]; [2; 10]; [2; 20]] Fill in the definition of count_prefix.
haskell infinite list of incrementing pairs
Create an infinite list pairs :: [(Integer, Integer)] containing pairs of the form (m,n), where each of m and n is a member of [0 ..]. An additional requirement is that if (m,n) is a legit member of the list, then (elem (m,n) pairs) should return True in finite time. An implementation of pairs that violates this requirement is considered a non- solution. ****Fresh edit Thank you for the comments, Lets see if I can make some progress**** pairs :: [(Integer, Integer)] pairs = [(m,n) | t <- [0..], m <- [0..], n <-[0..], m+n == t] Something like this? I just don't know where it's going to return True in finite time. I feel the way the question is worded elem doesn't have to be part of my answer. Just if you call (elem (m,n) pairs) it should return true. Sound right?
Ignoring the helper method, the list comprehension you have will list out all pairs but the order of elements is a problem. You'll have a infinitely many pairs like (0, m) which are followed by infinitely many pairs like (1, m). Of course elem will forever iterate all the (0, m) pairs never reaching (1, m) or (2, m) etc. I'm not sure why you have the helper method -- with it, you are only building a list of pairs like [(0,0), (1,1), (2,2), ...] because you've filtered on m = n. Was that part of the requirements? Like #hammar suggested, start with 0 = m + n and list out the pairs (m, n). Then list pairs (m, n) where 1 = m + n. Then your list will look like [(0,0), (0,1), (1,0), (0,2), (1,1), (2,0), ...].
The helper function ensures that pairs is a list of the form [ (0,0) , (1,1) , (2,2) ... ]. So elem ( m , n ) pairs can be implemented as: elem (m , n) _ | m == n = True | otherwise = False This is a constant time implementation.
I first posted Prelude> let pairs = [(m, n) | t <- [0..] , let m = head $ take 1 $ drop t [0..] , let n = head $ take 1 $ drop (t + 1) [0..]] Which, I believed answered the three conditions set by the professor. But hammar pointed out that if I chose this list as an answer, that is, the list of pairs of the form (t, t+1), then I might as well choose the list repeat [(0,0)] Well, both of these do seem to answer the professor's question, considering there seems to be no mention of the list having to contain all combinations of [0..] and [0..]. That aside, hammer helped me see how you can list all combinations, facilitating the evaluation of elem in finite time by building the infinite list from finite lists. Here are two other finite lists - less succinct than Hammar's suggestion of the diagonals - that seem to build all combinations of [0..] and [0..]: edges = concat [concat [[(m,n),(n,m)] | let m = t, n <- take m [0..]] ++ [(t,t)] | t <- [0..]] *Main> take 9 edges [(0,0),(1,0),(0,1),(1,1),(2,0),(0,2),(2,1),(1,2),(2,2)] which construct the edges (t, 0..t) (0..t, t), and oddSpirals size = concat [spiral m size' | m <- n] where size' = if size < 3 then 3 else if even size then size - 1 else size n = map (\y -> (fst y * size' + div size' 2, snd y * size' + div size' 2)) [(x, t-x) | let size' = 5, t <- [0..], x <- [0..t]] spiral seed size = spiral' (size - 1) "-" 1 [seed] spiral' limit op count result | count == limit = let op' = if op == "-" then (-) else (+) m = foldl (\a b -> a ++ [(op' (fst $ last a) b, snd $ last a)]) result (replicate count 1) nextOp = if op == "-" then "+" else "-" nextOp' = if op == "-" then (+) else (-) n = foldl (\a b -> a ++ [(fst $ last a, nextOp' (snd $ last a) b)]) m (replicate count 1) n' = foldl (\a b -> a ++ [(nextOp' (fst $ last a) b, snd $ last a)]) n (replicate count 1) in n' | otherwise = let op' = if op == "-" then (-) else (+) m = foldl (\a b -> a ++ [(op' (fst $ last a) b, snd $ last a)]) result (replicate count 1) nextOp = if op == "-" then "+" else "-" nextOp' = if op == "-" then (+) else (-) n = foldl (\a b -> a ++ [(fst $ last a, nextOp' (snd $ last a) b)]) m (replicate count 1) in spiral' limit nextOp (count + 1) n *Main> take 9 $ oddSpirals 3 [(1,1),(0,1),(0,2),(1,2),(2,2),(2,1),(2,0),(1,0),(0,0)] which build clockwise spirals of length 'size' squared, superimposed on hammar's diagonals algorithm.
I believe the solution to your task is: pairs = [(x,y) | u <- [0..], x <- [0..u], y <-[0..u] , u == x+y]