|
List Info
Thread: "ocaml_beginners"::[] Returning a pair (bool, maybe_value)
|
|
| "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  France |
2007-06-08 18:08:05 |
|
Hi !
Is it a good OCaml programming practice to write a function that returns a 2-uple :
the fst being a bool that tells if the snd result is valid or not ?
It happens to write things this way in C++, but here, not sure...
For example :
(* ---------------------------------------------------------- *)
type form = Atom of char
| Compound of form list
let string_of_char a = String.make 1 a
(* If a form list only contains char Atoms, build a string of these chars *)
let is_atom_list =
let non_atom_list = (false, "") in
List.fold_left (fun (carry_on, acc) e ->
if carry_on then
match e with
Atom a ->
(true, acc^(string_of_char a))
| Compound _ ->
non_atom_list
else
non_atom_list
)
(true, "")
let _ = is_atom_list [Atom 'a'; Compound []] (* -> ( false, "" ) *)
let _ = is_atom_list [Atom 'a'; Atom 'b'; Atom 'c'] (* -> ( true, "abc" ) *)
(* ---------------------------------------------------------- *)
A second question :
I read this programming advice that apparently sounds good :
the right use of exceptions is : an exceptional case.
In the above example, the case were all forms aren't all Atoms isn't unlikely.
So I obey to the rule and do not use exception.
However I wonder if it wouldn't be speeder to "cut" the fold run as soon as a non-char is met ?
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  United States |
2007-06-09 03:59:01 |
|
On Sat, Jun 09, 2007 at 01:08:05AM +0200, Fabrice Marchant wrote:
> Is it a good OCaml programming practice to write a function that
> returns a 2-uple : the fst being a bool that tells if the snd result
> is valid or not ?
Offhand, this seems like a case where using 'a option makes more
sense.
For example:
let do_something x =
(* ... stuff ... *)
if it_worked then
(true, 5)
else
(false, 10)
;;
and:
let (a,b) = do_something y in
if a then
do_something_else b
else
do_something_different b
Now, compare that to this:
let do_something x =
if it_worked then
Some 5
else
None
and
match do_something y with
None -> do_something_different ()
| Some z -> do_something_else z
I find the second form cleaner, and much more OCaml-y.
--Mac
--
Julian "Mac" Mason mac%40cs.duke.edu">mac cs.duke.edu
[Non-text portions of this message have been removed]
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  Belgium |
2007-06-09 04:56:16 |
|
On Sat, 9 Jun 2007, Fabrice Marchant < fabrice.marchant%40orange.fr">fabrice.marchant orange.fr> wrote:
>
> Is it a good OCaml programming practice to write a function that
> returns a 2-uple : the fst being a bool that tells if the snd result
> is valid or not ?
No because the result can still mistakenly be used when it is invalid.
Like it was mentioned already you can use an option return value. You
can also use an exception to declare the result invalid (to choose
w.r.t. the option return value, see what your usage of is_atom_list
will become at various places in your code):
let is_atom_list =
List.fold_left (fun acc -> function
| Atom a -> acc^(string_of_char a)
| Compound _ -> failwith "is_atom_list"
) ""
Note also that building a string by concatenating chars is dead slow
(you reallocate memory for all concatenations), it is much better to
allocate the string once :
let is_atom_list l =
let s = String.create (List.length l) in
let _ = List.fold_left (fun i -> function
| Atom a -> s.[i] <- a; i+1
| Compound _ -> failwith "is_atom_list"
) 0 l in
s
On a simple list like [Atom 'a'; Atom 'b'; Atom 'c'] the second is
vastly faster : (see http://ocaml-benchmark.sourceforge.net/doc/Benchmark.html
for how to read the results):
Rate ^ <-
^ 1670724+- 6213/s -- -88%
<- 14388408+-33766/s 761% --
> In the above example, the case were all forms aren't all Atoms
> isn't unlikely. So I obey to the rule and do not use exception.
> However I wonder if it wouldn't be speeder to "cut" the fold run as
> soon as a non-char is met ?
IMHO, clarity and elegance come before rules. Look how the two
solutions influence the rest of your code and decide.
My 2 cents,
ChriS
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  France |
2007-06-09 02:59:42 |
|
On Sat, 9 Jun 2007 01:59:01 -0700
Mac Mason < mac%40cs.duke.edu">mac cs.duke.edu> wrote:
> On Sat, Jun 09, 2007 at 01:08:05AM +0200, Fabrice Marchant wrote:
> > Is it a good OCaml programming practice to write a function that
> > returns a 2-uple : the fst being a bool that tells if the snd result
> > is valid or not ?
>
> Offhand, this seems like a case where using 'a option makes more
> sense.
>
> For example:
>
> let do_something x =
> (* ... stuff ... *)
> if it_worked then
> (true, 5)
> else
> (false, 10)
> ;;
>
> and:
>
> let (a,b) = do_something y in
> if a then
> do_something_else b
> else
> do_something_different b
>
> Now, compare that to this:
>
> let do_something x =
> if it_worked then
> Some 5
> else
> None
>
> and
>
> match do_something y with
> None -> do_something_different ()
> | Some z -> do_something_else z
>
> I find the second form cleaner, and much more OCaml-y.
Thanks Mac !
Of course you are right ! "Some / None" absolutely improves the code here.
I realize the difficult thing, in learning OCaml, is not to understand the different notions :
the problem is - for me - to remember to use, at right place, the right method among the numerous powerful means the language offers to us...
Best Regards
Fabrice
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  United Kingdom |
2007-06-09 06:34:21 |
|
On Saturday 09 June 2007 00:08:05 Fabrice Marchant wrote:
> Is it a good OCaml programming practice to write a function that returns a
2-uple :
> the fst being a bool that tells if the snd result is valid or not ?
As others have already explained, an option type is preferable.
> I read this programming advice that apparently sounds good :
> the right use of exceptions is : an exceptional case.
This is awful advice born of imperative languages with slow exception
handling.
In OCaml, you should aim to write short, clear code in OCaml and use
exceptions whenever it helps. Your chosen example is exactly the kind of
function that should use exceptions even if they are likely to occur.
Note that OCaml's exceptions are very fast, ~6x faster than C++ and ~600x
faster than C#.
> In the above example, the case were all forms aren't all Atoms isn't
> unlikely. So I obey to the rule and do not use exception.
> However I wonder if it wouldn't be speeder to "cut" the fold run as soon
> as a non-char is met ?
And this is ideally suited to using an exception.
I would write something like:
let unbox_atom = function
| Atom c -> c
| Compound _ -> raise Not_found
let ( |> ) x f = f x
let ( << ) f g x = f(g x)
let is_atom_list =
String.concat "" <<
List.map (String.make 1 << unbox_atom)
The two aggregate operators are borrowed from F#.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?e
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  France |
2007-06-10 02:35:46 |
|
THANKS A LOT CHRIS !
> > IS IT A GOOD OCAML PROGRAMMING PRACTICE TO WRITE A FUNCTION THAT
> > RETURNS A ... BOOL THAT TELLS US ABOUT THE RESULT
> NO BECAUSE THE RESULT CAN STILL MISTAKENLY BE USED WHEN IT IS INVALID.
I SEE !
> LIKE IT WAS MENTIONED ALREADY YOU CAN USE AN OPTION RETURN VALUE.
I WROTE THIS TO USE NONE/SOME AS SOON AS I RECEIVED MAC EXPLANATIONS :
HTTP://FABRICE.MARCHANT.FREE.FR/CODE/OPTION.ML
HOWEVER, I WAS ONLY ABLE TO PRODUCE A DULL PIECE OF CODE...
> YOU CAN ALSO USE AN EXCEPTION TO DECLARE THE RESULT INVALID (TO CHOOSE
> W.R.T. THE OPTION RETURN VALUE, SEE WHAT YOUR USAGE OF IS_ATOM_LIST
> WILL BECOME AT VARIOUS PLACES IN YOUR CODE):
(I ONLY USE IT ONE TIME.)
I REWROTE THE THINGS AFTER TO HAVE READ JON'S CODE SNIPPETS AND
NOTE IT WAS FAR EASIER TO USE EXCEPTION INDEED.
> NOTE ALSO THAT BUILDING A STRING BY CONCATENATING CHARS IS DEAD SLOW
> (YOU REALLOCATE MEMORY FOR ALL CONCATENATIONS), IT IS MUCH BETTER TO
> ALLOCATE THE STRING ONCE :
>
> LET IS_ATOM_LIST L =
> LET S = STRING.CREATE (LIST.LENGTH L) IN
> LET _ = LIST.FOLD_LEFT (FUN I -> FUNCTION
> | ATOM A -> S.[I] <- A; I+1
> | COMPOUND _ -> FAILWITH "IS_ATOM_LIST"
> ) 0 L IN
> S
I UNDERSTAND BUT MAYBE THIS PROBLEM DISAPPEARS WITH THE STRING.CONCAT THAT JON USES.
> ON A SIMPLE LIST LIKE [ATOM 'A'; ATOM 'B'; ATOM 'C'] THE SECOND IS
> VASTLY FASTER : (SEE HTTP://OCAML-BENCHMARK.SOURCEFORGE.NET/DOC/BENCHMARK.HTML
> FOR HOW TO READ THE RESULTS):
THANKS CHRIS, I DIDN'T KNOW THIS USEFUL TOOL.
BEST REGARDS,
FABRICE
---------------------
S'IL VOUS PLAîT CHRIS, COMMENT FAITES-VOUS POUR QU'UN LOGO DEBIAN APPARAISSE, AVEC VOTRE MESSAGE, DANS MON SYLPHEED-CLAWS / ETCH ?
JE N'AVAIS JAMAIS VU çA !
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  France |
2007-06-10 02:36:27 |
|
Thanks a lot Jon for these code snippets I really found stunningly elegant.
> > I read this programming advice that apparently sounds good :
> > the right use of exceptions is : an exceptional case.
>
> This is awful advice born of imperative languages with slow exception
> handling.
OK : Exceptions are good.
>
> I would write something like:
>
> let unbox_atom = function
> | Atom c -> c
> | Compound _ -> raise Not_found
>
> let ( |> ) x f = f x
> let ( << ) f g x = f(g x)
>
> let is_atom_list =
> String.concat "" <<
> List.map (String.make 1 << unbox_atom)
So I'm happy to rewrite my code concisely your way :
(* ---------------------------------------------------------- *)
type form = Atom of char
| Compound of form list
let unbox_atom = function
| Atom c -> c
| Compound _ -> raise Not_found
let string_of_char = String.make 1
let ( << ) f g x = f(g x)
let atom_list =
String.concat "" << List.map (string_of_char << unbox_atom)
let rec string_of_form =
function
Atom a ->
"`" ^ string_of_char a
| Compound l ->
match l with
[] -> "()"
| _ -> try atom_list l with
Not_found ->
"(" ^
((String.concat " " << List.map string_of_form) l) ^
")"
let nil = Compound []
let f1 = Atom 'a'
let f2 = Atom 'b'
let f3 = Compound [f1; f2; Atom '*']
let f4 = Compound [nil; f1; Compound [f2]; f3; Compound [f3]]
let _ = Printf.printf "%sn" (string_of_form f4)
(* ---------------------------------------------------------- *)
The question I think about now is :
How to decide what to use option vs exception ?
I did a trial with Some / None, without using exception and the result was not elegant at all...
Best regards,
Fabrice
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  United Kingdom |
2007-06-10 06:44:46 |
|
On Sunday 10 June 2007 08:36:27 Fabrice Marchant wrote:
> The question I think about now is :
> How to decide what to use option vs exception ?
Use options when you want to store the result or when you need tail recursion.
Use exceptions when they let you skip superfluous code or when you want to
avoid the performance hit of allocation.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
OCaml for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/?e
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  France |
2007-06-10 11:34:36 |
|
> Use options when you want to store the result or when you need tail recursion.
> Use exceptions when they let you skip superfluous code
3) > or when you want to avoid the performance hit of allocation.
Thank you, Jon for these advices !
However, I do not understand 3rd part.
Please, could you explain, just a bit, how exceptions can avoid this "performance hit of allocation" ?
Kind regards
Fabrice
__._,_.___
.
__,_._,___
|
| Re: "ocaml_beginners"::[]
Returning a pair (bool, maybe_value) |
  United States |
2007-06-10 09:03:55 |
|
On Jun 10, 2007, at 1:36 AM, Fabrice Marchant wrote:
> OK : Exceptions are good.
Don't let Brian Hurt hear you say that...
Seriously, you should make sure exceptions are what you want to use
when you use them, they don't behave like variants, so if you're not
sure what you're doing they may produce unexpected results.
> So I'm happy to rewrite my code concisely your way :
I'm a bit confused as to why you're using exceptions and the extra
atom_list function, etc at all here. Doesn't this do what you want?
type form = Atom of char
| Compound of form list
let rec string_of_form = function
| Atom a -> let a' = String.make 2 '`' in a'.[1] <- a; a'
| Compound [] -> "()"
| Compound l -> "("^String.concat " " (List.map string_of_form l)^")"
let nil = Compound []
let f1 = Atom 'a'
let f2 = Atom 'b'
let f3 = Compound [f1; f2; Atom '*']
let f4 = Compound [nil; f1; Compound [f2]; f3; Compound [f3]]
let _ = Printf.printf "%sn" (string_of_form f4)
William D. Neumann
"I eat T-bone steaks, I lift barbell plates, I'm sweeter than a
German chocolate cake. I'm the reflection of perfection, the number
one selection. I'm the man of the hour, the man with the power, too
sweet to be sour. The ladies' pet, the men's regret, where what you
see is what you get, and what you don't see, is better yet."
--Superstar Billy Graham
__._,_.___
.
__,_._,___
|
|
|