I just begin OCaml (and functional programming) today and I'm trying to code a function that count the number of occurrences of "value" into an array (tab).
I tried :
let rec count_occ tab value =
let rec count_rec idx time = function
| tab.length - 1 -> time
| _ when tab.(indice) == value-> count_rec (idx + 1) (time + 1)
| _ -> count_rec (indice + 1) time
in
count_rec 0 0
;;
Unfortunately, it doesn't compile because of a syntax error, and I don't find the solution.
let rec count_occ tab value =
This rec above is not necessary.
let rec count_rec idx time = function
| tab.length - 1 -> time
You cannot match against an expression. You want to use guards like you did on the next line, or if statements to test something like this. tab.length also does not exist as tab is an array, not a record with a length field. You want Array.length tab.
Really though, you don't want the function at all. function is the same as fun x -> match x with, and would imply that count_rec has type, int -> int -> int -> int.
| _ when tab.(indice) == value-> count_rec (idx + 1) (time + 1)
indices is not declared; lets assume you meant idx. Also, == is physical equality, you really want =.
| _ -> count_rec (indice + 1) time
in
count_rec 0 0
You're off to a good start, the basics of your recursion are correct although one edge case is incorrect, but a minor issue you should be able to resolve once you have the syntactic issues fixed.
finnaly I post my final code :
let count_occ tab value =
let rec count_rec idx time =
if (Array.length tab) = idx then
time
else if (tab.(idx)) = value then
count_rec (idx + 1) (time + 1)
else
count_rec (idx + 1) time
in
count_rec 0 0
;;
Related
I have the following code written in Ocaml to try and generate the first 50 catalan numbers:
let rec f n:int64=
if n<1 then 1L
else (4*n-2)*f((n-1L))/(n+1L)
;;
for i = 0 to 50 do
Printf.printf "%d\n"(f i)
done;
But the problem is that the recursion function doesn't seem to accept Int64 values and seems to want Int instead despite me notating n as int64:
File "/proc/self/fd/0", line 3, characters 19-21:
3 | else (4*n-2)*f((n-1L))/(n+1L)
^^
Error: This expression has type int64 but an expression was expected of type
int
exit status 2
Is there a way to ensure I can int64 numbers here with recursion?
Your problem isn't recursion per se, it's that the operators in OCaml are strongly typed. So the - operator is of type int -> int -> int.
Without getting into lots of fussing with the syntax, the easiest fix is probably to use the named functions of the Int64 module. You can use Int64.sub rather than -, for example.
You can use the notation Int64.(... <expr> ...) to avoid repeating the module name. If you rewrite your code this way, you get something like this:
let rec f (n : int64) : int64 =
Int64.(
if n < 1L then 1L
else
mul (sub (mul 4L n) 2L)
(f (div (sub n 1L) (add n 1L)))
)
Looking at the results computed by this function, they don't look like Catalan numbers to me. In fact the 50th Catalan number is too large to be represented as an int64 value.
So there is still some work to do. But this is how to get past the problem you're seeing (IMHO).
If you really want to work with such large numbers, you probably want to look at the Zarith module.
Submitted as an additional suggestion to Jeffrey's answer: whether using Int64 or Zarith, you might create a module defining arithmetic operators and then locally open that to clean up your code.
E.g.
module Int64Ops =
struct
let ( + ) = Int64.add
let ( - ) = Int64.sub
let ( * ) = Int64.mul
let ( / ) = Int64.div
end
let rec f n =
Int64Ops.(
if n < 1L then 1L
else (4L * n - 2L) * f (n - 1L) / (n + 1L)
)
Or you could use a functor to make it easier to work with multiple different types of numbers.
module type S =
sig
type t
val add : t -> t -> t
val sub : t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
end
module BasicArithmeticOps (X : S) =
struct
type t = X.t
let ( + ) = X.add
let ( - ) = X.sub
let ( * ) = X.mul
let ( / ) = X.div
end
# let module A = BasicArithmeticOps (Float) in
A.(8. + 5.1);;
- : float = 13.1
# let module A = BasicArithmeticOps (Int) in
A.(8 + 3);;
- : int = 11
# let module A = BasicArithmeticOps (Int64) in
A.(4L + 3L);;
- : int64 = 7L
I'm trying to wrap my head around functional programming using F#. I'm sticking to purely mathematical problems for now.
My current problem is simple enough: to write a function that takes an integer N and outputs a list of all the factors of N
Because of the similarities between sequences and C# IEnumerables formed by yield return I got this solution:
let seqFactorsOf n =
seq { for i in 2 .. (n / 2) do if n % i = 0 then yield i }
I don't think lists can be generated that way, though, so I turned to List.unfold:
let listFactorsOf n =
2 |> List.unfold (fun state ->
if state <= n / 2 then
if state % 2 = 0 then
Some (state, state + 1)
else
//need something here to appease the compiler. But what?
else
None)
My other attempt uses the concept of matching, with which I'm almost totally unfamiliar:
let listFactorsOf_2 n =
2 |> List.unfold(fun state ->
match state with
| x when x > n / 2 -> None
| x when n % x = 0 -> Some(x, x + 1)
//I need a match for the general case or I get a runtime error
)
Is there a way to create such list using List.unfold? Please notice that I'm a beginner (I started F# 3 days ago) and the documentation is not very kind to newbies, so if you'd try to be as didactic as possible I would appreciate it a lot.
First - yes, of course lists can be generated using that for..in syntax (it's called "list comprehensions" by the way). Just put the whole thing in square brackets instead of seq { }:
let seqFactorsOf n =
[ for i in 2 .. (n / 2) do if n % i = 0 then yield i ]
As for unfold - every iteration is required to either produce an element of the resulting list (by returning Some) or to signal end of iteration (by returning None). There is nothing you can return from the body of unfold to indicate "skipping" the element.
Instead, what you have to do is to somehow "skip" the unwanted elements yourself, and only ever return the next divisor (or None).
One way to do that is with a helper function:
let rec nextDivisor n i =
if n % i = 0 then Some i
else if i >= n/2 then None
else nextDivisor n (i+1)
Let's test it out:
nextDivisor 16 3
> Some 4
nextDivisor 16 5
> Some 8
nextDivisor 16 10
> None
Now we can use that in the body of unfold:
let listFactorsOf n =
2 |> List.unfold (fun state ->
match nextDivisor n state with
| Some d -> Some (d, d + 1)
| None -> None
)
As a bonus, the construct match x with Some a -> f a | None -> None is a well-known and widely used concept usually called "map". In this particular case - it's Option.map. So the above can be rewritten like this:
let listFactorsOf n =
2 |> List.unfold (fun state ->
nextDivisor n state
|> Option.map (fun d -> d, d+1)
)
let countA =0 in
let countC =0 in
let countG =0 in
let countT =0 in
let countChar x =
match x with
'A' -> countA = countA + 1
|'C'-> countC = countC + 1
|'G' -> countG = countG + 1
|'T'-> countT = countT + 1
;;
I am getting a syntax error but I don't understand why, i'm still pretty new to Ocaml.
Your syntax error is caused by the fact that your last let doesn't have an in after it. This, in turn, is caused by the fact that your countChar function isn't defined at the outermost level (of a module). If you want to define a series of top-level names, you should define them all without in:
let countA = 0
let countC = 0
let countChar x = ...
So, that's your syntax problem. However, there are many other problems with this code.
The most obvious two are (A) you're expecting to be able to change the values of countA and so on. But they are immutable values, you can't change them. (B) You are using = as if it's an assignment operator. But in OCaml this is a comparison operator. Your code is just comparing countA against countA + 1. So of course the result is false.
It is definitely worth learning how to compute with immutable values, so I would try to fix this code by learning how to carry the cumulative counts as function parameters and return them at the end. But if you insist on coding imperatively, you will have to use references for your counts.
I also don't see any code that works on a string. Your countChar function (as the name implies) works on just one character.
Update
Here is a function that counts how many even and odd ints appear in an array. It works without mutating anything:
let eoa array =
let rec inner n (evenct, oddct) =
if n >= Array.length array then
(evenct, oddct)
else
let newcounts =
if array.(n) mod 2 = 0 then (evenct + 1, oddct)
else (evenct, oddct + 1)
in
inner (n + 1) newcounts
in
inner 0 (0, 0)
Here's how it looks when you run it:
# eoa [| 3; 1; 4; 1; 5; 9; 2 |];;
- : int * int = (2, 5)
Following my previous post here , I tried to do what was suggested and convert the code
into a Tail-recursion method with let .
The original code - which does not work (due to using val inside if condition) :
fun func() =
val decimal = 0 (* the final result *)
val multiple = 0 (* keeps track of multiples, eg. In XXV, X would be a multiple *)
val current = 0 (* the digit currently being processed *)
val top = 0 (* value of the last element in the list *)
val last_add = 0 (* the last digit that wasn't a multiple, or subtraction operation *)
val last_sub = 0
val problem = 0 (* if value is 1 then there is a problem with the input *)
val myList = [1,2,3,4,5] (* the list has more values *)
while (myList <> []) (* run while the list is not empty *)
val current = tl(myList) (* grab the last element from the list *)
val myList = tl(myList) (* remove the last element from the list *)
val top = tl(myList) (* grab the value at the end of the list *)
if ( myList <> []) andalso (current > top))
then
val decimal = decimal + current - top
val last_sub = top;
val myList = tl(myList)
else
if ( (myList = []) andalso (current = top))
then val decimal = decimal + current
val multiple = multiple + 1
else
if (last_sub = current)
then val problem = 1
else
val decimal = decimal + current
val multiple = 0
val last_add = current
And the code as a tail-recursion method :
fun calc [] = 0
|calc [x] = x
|calc (head::tail) =
let
val decimal = 0
val multiple = 0
val current = 0
val top = 0
val last_add = 0
val last_sub = 0
val problem = 0
val doNothing = 0
in
let
val current = hd(rev(head::tail)) (* grab the last element *)
val head::tail = rev(tl(rev(head::tail))) (* POP action - remove the last element from the list *)
val top = hd(rev(head::tail)) (* grab the new last element after removing *)
in
if (current > top) then
let
val decimal = decimal + current - top
val last_sub = top
val head::tail = rev(tl(rev(head::tail))) (* POP action - remove the last element from the list *)
in
calc(head::tail)
end
else
if ( (head::tail = []) andalso (current = top))
then let
val decimal = decimal + current
val multiple = multiple + 1
in
calc(head::tail)
end
else
if (last_sub <> current)
then let
val decimal = decimal + current
val multiple = 0
val last_add = current
in
calc(head::tail)
end
else
(* do nothing *)
val doNothing = 0
end
end;
However , when I try to enter :
calc([0,100,20,30,4,50]);
I get :
uncaught exception Bind [nonexhaustive binding failure]
raised at: stdIn:216.13-216.50
I know the code is very hard to read and pretty long , but it would be greatly appreciated
if someone could explain to me how to fix it , or help me find the reason for this output .
Thanks
You have a few issues with your code.
First of all, you can use last to grab the last element of a list. See the List documentation for more info. But unless you have a really good reason to do so, it's easier and much more efficient to simply start from the beginning of the list and pop elements off the beginning as you recurse. You already have the first element bound to head in your code using pattern matching.
Secondly, unless you use refs (which you probably don't want to do) there are no variables in Standard ML, only values. What this means is that if you want to carry state between invocations, any accumulators need to be parameters of your function. Using a helper function to initialize accumulators is a common pattern.
Third, instead of comparing a list to [] to test if it's empty, use the null function. Trust me on this. You'll get warnings using = because of subtle type inference issues. Better yet, use a pattern match on your function's parameters or use a case statement. Pattern matching allows the compiler to tell you whether you've handled all possible cases.
Fourth, SML typically uses camelCase, not snake_case, for variable names. This is more stylistic, but as you write more code and collaborate, you're going to want to fit with the conventions.
Fifth, when you do recursion on a list, don't try to look at multiple values in the list. This complicates things. Treat it as a head element and tail list, and everything will become much simpler. In my code, instead of keeping current in the list, I did this by splitting it out into a separate parameter. Have a base case where you simply return the answer from one of your accumulators, and a recursive case where you recurse with updated accumulator values and a single value popped from your list. This eliminates the problem scenario.
I'm not sure if this logic is correct since I don't know what you're trying to calculate, but check out this code which illustrates some of the things I talked about.
(* This is the helper function which takes accumulators as
parameters. You shouldn't call this directly. *)
fun calc' decimal _ _ _ _ [] =
(* We processed everything in the list. Just return the accumulator. *)
decimal
| calc' decimal multiple lastAdd lastSub current (top::tail) =
(* This case is for when there are 1 or more elements in the list. *)
if current > top then
calc' (decimal + current - top) multiple lastAdd top top tail
else if current = top then
calc' (decimal + current) (multiple + 1) lastAdd lastSub top tail
else
calc' (decimal + current) 0 current lastSub top tail
(* This is the function you should call. *)
fun calc [] = 0
| calc [_] = 0 (* Given a single-element list. *)
| calc (x::xs) =
(* Apply the helper with correct initial values. *)
calc' 0 0 0 0 x xs
In a functional language, instead of assigning to a variable when you want to change it, simply recurse and specify the new value for the correct parameter. This is how you write a "loop" in a functional language using recursion. As long as you only use tail-recursion, it will be just as efficient as a while loop in your favorite imperative language.
I am currently doing reasonably well in functional programming using F#. I tend, however, to do a lot of programming using recursion, when it seems that there are better idioms in the F#/functional programming community. So in the spirit of learning, is there a better/more idiomatic way of writing the function below without recursion?
let rec convert line =
if line.[0..1] = " " then
match convert line.[2..] with
| (i, subline) -> (i+1, subline)
else
(0, line)
with results such as:
> convert "asdf";;
val it : int * string = (0, "asdf")
> convert " asdf";;
val it : int * string = (1, "asdf")
> convert " asdf";;
val it : int * string = (3, "asdf")
Recursion is the basic mechanism for writing loops in functional languages, so if you need to iterate over characters (as you do in your sample), then recursion is what you need.
If you want to improve your code, then you should probably avoid using line.[2..] because that is going to be inefficient (strings are not designed for this kind of processing). It is better to convert the string to a list and then process it:
let convert (line:string) =
let rec loop acc line =
match line with
| ' '::' '::rest -> loop (acc + 1) rest
| _ -> (acc, line)
loop 0 (List.ofSeq line)
You can use various functions from the standard library to implement this in a more shorter way, but they are usually recursive too (you just do not see the recursion!), so I think using functions like Seq.unfold and Seq.fold is still recursive (and it looks way more complex than your code).
A more concise approach using standard libraries is to use the TrimLeft method (see comments), or using standard F# library functions, do something like this:
let convert (line:string) =
// Count the number of spaces at the beginning
let spaces = line |> Seq.takeWhile (fun c -> c = ' ') |> Seq.length
// Divide by two - we want to count & skip two-spaces only
let count = spaces / 2
// Get substring starting after all removed two-spaces
count, line.[(count * 2) ..]
EDIT Regarding the performance of string vs. list processing, the problem is that slicing allocates a new string (because that is how strings are represented on the .NET platform), while slicing a list just changes a reference. Here is a simple test:
let rec countList n s =
match s with
| x::xs -> countList (n + 1) xs
| _ -> n
let rec countString n (s:string) =
if s.Length = 0 then n
else countString (n + 1) (s.[1 ..])
let l = [ for i in 1 .. 10000 -> 'x' ]
let s = new System.String('x', 10000)
#time
for i in 0 .. 100 do countList 0 l |> ignore // 0.002 sec (on my machine)
for i in 0 .. 100 do countString 0 s |> ignore // 5.720 sec (on my machine)
Because you traverse the string in a non-uniform way, a recursive solution is much more suitable in this example. I would rewrite your tail-recursive solution for readability as follows:
let convert (line: string) =
let rec loop i line =
match line.[0..1] with
| " " -> loop (i+1) line.[2..]
| _ -> i, line
loop 0 line
Since you asked, here is a (bizarre) non-recursive solution :).
let convert (line: string) =
(0, line) |> Seq.unfold (fun (i, line) ->
let subline = line.[2..]
match line.[0..1] with
| " " -> Some((i+1, subline), (i+1, subline))
| _ -> None)
|> Seq.fold (fun _ x -> x) (0, line)
Using tail recursion, it can be written as
let rec convert_ acc line =
if line.[0..1] <> " " then
(acc, line)
else
convert_ (acc + 1) line.[2..]
let convert = convert_ 0
still looking for a non-recursive answer, though.
Here's a faster way to write your function -- it checks the characters explicitly instead of using string slicing (which, as Tomas said, is slow); it's also tail-recursive. Finally, it uses a StringBuilder to create the "filtered" string, which will provide better performance once your input string reaches a decent length (though it'd be a bit slower for very small strings due to the overhead of creating the StringBuilder).
let convert' str =
let strLen = String.length str
let sb = System.Text.StringBuilder strLen
let rec convertRec (count, idx) =
match strLen - idx with
| 0 ->
count, sb.ToString ()
| 1 ->
// Append the last character in the string to the StringBuilder.
sb.Append str.[idx] |> ignore
convertRec (count, idx + 1)
| _ ->
if str.[idx] = ' ' && str.[idx + 1] = ' ' then
convertRec (count + 1, idx + 2)
else
sb.Append str.[idx] |> ignore
convertRec (count, idx + 1)
// Call the internal, recursive implementation.
convertRec (0, 0)