3
votes

I want to define a function check_char_fun: (char -> 'a) -> (char ->' a) -> bool that, given two functions on char, return true when both functions are the same (ie, when they are exactly the same behavior on every one of the possible values of a char) and false otherwise.

let check_char_fun f1 f2 =
let aux = true
for i=0 to 255 do
    if (f1 (char_of_int i))=(f2 (char_of_int i))
    then aux=false;
done;
if aux=true
then true
else false;;

I am learning OCaml, so I don't know what can I do.

4

4 Answers

2
votes

You're nearly there:

let check_char_fun f1 f2 =
  let aux = ref true in
  for i = 0 to 255 do
    if (f1 (char_of_int i)) = (f2 (char_of_int i)) then aux := false
    else ()
  done;
  !aux

Unlike the variables in imperative languages, bindings in OCaml are immutable by default. To create a real variable, we create a bool ref which is mutable and can be changed from within the loop.

OCaml does not have a distinction between statements and expressions like the imperative languages: There are only expressions! Thats why you always need the else clause to an if; this ways the resulting expression always returns a value (in both if and else case) the type of which must be the same -- in this case of type unit (the type of the value () -- which would be void in C).

Your code is not very OCaml-like, but thats what I personally love about OCaml: The functional style is not forced down your throat and you can implement algorithms in an imperative style without entering the academic ivory tower.

2
votes

First, you have to have a definition for what a "behavior" is. If your functions can raise exceptions the problem gets harder. Your code assumes the functions always return a value, which seems like a good simplification for a beginning problem.

You're also using the (somewhat out-of-date) definition of character that OCaml uses, in that codes are limited to the range 0 .. 255. This also seems OK.

So the only problem I see in your code is that you're expecting to be able to change the value of the aux variable. Variables in OCaml are immutable: you can't change the value that they're bound to.

If you want to keep your code mostly as it is, you can change aux so its value is a reference to a bool. Then you can change the boolean value inside the reference (while aux remains bound to the same reference).

To make a reference to a bool and change the value:

# let x = ref true;;
val x : bool ref = {contents = true}
# !x;;
- : bool = true
# x := false;;
- : unit = ()
# !x;;
- : bool = false

(One of the reasons to study OCaml is to learn how to work with immutable values. So I'd suggest looking for other ways to solve the problem that don't require the use of references.)

1
votes
let rec range i j = 
  if i > j then [] else i :: (range (i+1) j);;

let check_char_fun f1 f2 =
  let lc = List.map char_of_int (range 0 255) in
  List.for_all (fun c -> (f1 c) = (f2 c)) lc;;

test:

#let id x =x;;
val id : 'a -> 'a = <fun>
# check_char_fun id id;;
- : bool = true
# check_char_fun id (fun x -> 'a');;
- : bool = false

Or:

exception Fails_in of char;;
let check_char_fun f1 f2 =
  let lc = List.map char_of_int (range 0 255) in
  List.iter (fun c ->  
    if (f1 c) <> (f2 c) then raise (Fails_in c)
  ) lc;;

# try (
  check_char_fun id id
) with Fails_in c -> Printf.printf "Diff(%d)(%c)" (int_of_char c) c
;;
  - : unit = ()


# try (
  check_char_fun id (fun x -> 'a')
) with Fails_in c -> Printf.printf "Diff(%d)(%c)" (int_of_char c) c
;;      
Diff(0)()- : unit = ()
1
votes

The following applies each function to each character value in the 0 .. 255 range and compares their results, but it does not check for cases where a function raises an exception or causes a side effect elsewhere:

open Core.Std
let check_char_fun f1 f2 =
  let chars = List.map ~f:char_of_int (List.range 0 256) in
  List.for_all ~f:(fun c -> (f1 c) = (f2 c)) chars