On Fri, Dec 22, 2006 at 01:31:50AM +0100, Philippe Strauss wrote:
> first I define a function which take a list, usually like
> the following: [-1; -1; 1; 1], and change the sign of it's
> component: should output [1; 1; -1; -1].
>
> I wrote this:
>
> Objective Caml version 3.09.2
>
> let rec negate seq = match seq with
> hd::tl -> -hd :: negate tl
> | [] -> [];;
> val negate : int list -> int list = <fun>
>
> it's working fine.
Looks good. In the spirit of functional programmers being verse terse
(which we probably got from mathematicians), let me point out one or
two things that will make this even easier:
If you define a function using the "function" keyword, it
automatically adds an argument to your function, and pattern-matches
against it. For example, you could have written the above as:
let rec negate = function
[] -> []
| hd::tl -> -hd::negate tl
;;
(order of things and indentation tweaked for my own edification, but
without any actual effect on what the code does)
Either of those ways in an excellent example of why pattern-matching
is such a wonderful thing to have.
I'm going to assume that you're also new to functional programming in
general - if not, at least I'm showing you some syntax for things you
already know...
What your negate function really wants to do is apply a function
("negate a single value") to every element of a list. There's actually
already a function for this, called "map". For lists, it's in the List
module, so you say List.map, and for Arrays, Array.map.
# List.map;;
- : ('a -> 'b) -> 'a list -> 'b list = <fun>
So, given a function and a list, return the list of that function
applied to every element of the list. For example:
# let neg_one x = -x;;
val neg_one : int -> int = <fun>
# List.map neg_one [1;2;3];;
- : int list = [-1; -2; -3]
In fact, what I've called neg_one is built in: it's ~- for ints, and
~-. for floats.
This is bit bizarre; the one-argument - operator (like you used in
negate, above) isn't really a function; it's dealt with by the parser.
The negation function is ~-:
# (~-);;
- : int -> int = <fun>
# (~-) 5;;
- : int = -5
So, now we can write negate like this:
let negate seq = List.map (~-) seq
Believe it or not, we can make this even more terse. Consider the type
of List.map:
# List.map;;
- : ('a -> 'b) -> 'a list -> 'b list = <fun>
And if we give it one argument (the function) but not the rest:
# List.map (~-);;
- : int list -> int list = <fun>
But that's the same type as negate, from above. In fact, it does the
same thing:
# let negate = List.map (~-);;
val negate : int list -> int list = <fun>
# negate [1;2;3];;
- : int list = [-1; -2; -3]
This is called "point-free" notation: the "points" are arguments that
are in both the function definition (negate seq) and calls inside the
definition (List.map (~-) seq).
> let rec golay (a, b) depth maxdepth =
> if depth = maxdepth then
> (a, b)
> else
> golay (a
b, a
negate b) depth+1 maxdepth;;
> ---------------------------------
> This expression has type 'a -> 'b * 'c but is here used with type int
>
> I need to return two list, hence the tuple of list of integers.
> What m'I doing wrong?
Stuff left-associates like crazy, so the implied parentheses look like
this:
(golay (a
b, a
negate b) depth)+;1 maxdepth);;
which has type 'a -> 'b * 'c because it expects an extra argument
(maxdepth) but instead thinks it's being treated like an int (because
you're adding 1 to it)
This quirk takes about three programs to get used to, and then you
stop noticing it.
Good grief, that was a really long e-mail.
--Mac
[Non-text portions of this message have been removed]
.