let rec map_test f test l =
(
match l with
[] -> []
| head :: tail -> [(if test head then f head else head)] @ (map_test f test tail)
);;
Formatting O'Caml code
I'm having considerable trouble applying my typical indenting behavior (or in fact, any indenting behavior) to O'Caml in a way that makes sense. Here's the snip I'm messing with:
As is, it's already a mess, and I'm not sure what's traditional to make this look pretty and nice.
Any reason why you're creating a list of one-element lists?
Either way, I would indent it as:
Or (but this is beyond the scope of the thread) :
Either way, I would indent it as:
let rec map_test f test = function | [] -> [] | h::t -> (if test h then f h else h) :: (map_test f test t)
Or (but this is beyond the scope of the thread) :
let map_test f test = List.map (fun x -> if test x then f x else x)
Quote:Original post by ToohrVykI thought @ appended lists. What exactly is the difference between :: and @? Actually, I don't really understand why your code differs but does the same thing. "match" removed and just "function" there, for example.
Any reason why you're creating a list of one-element lists?
Quote:Original post by Promit
I thought @ appended lists. What exactly is the difference between :: and @?
Disregard my comment, I had read "::" instead of "@" in your code. @ appends arbitrary lists (which means both lists are evaluated and concatenated in potentially linear time), while :: constructs a new list from a head and a tail (which is universally faster than concatenation, and draws an elegant parallel with pattern matching).
Also, [a] is syntactic sugar for a::[].
Quote:Actually, I don't really understand why your code differs but does the same thing. "match" removed and just "function" there, for example.
let a x = match x with is equivalent with let a = function, so the second is usually more idiomatic because it's shorter. let a = fun is slightly different in its pattern matching potential (it can pattern-match several arguments at once).
:: is the 'cons' operator and appends an element to the front of the list. @ joins two lists. In your case...I don't think there is much of a speed difference.
But normally, a @ b is essentially just:
a' = List.reverse(a), then a loop to :: each element in a' onto b.
...if I am not mistaken, which I may be. Either way, @ is 'slow'.
As for your indenting behavior ... well, I don't use OCaml, but SML is similar enough. As far as it goes, I don't see anything particularly wrong. Personally I just prefer to use 3 spaces so you don't get so much whitespace -- but you have the general idea in my opinion.
With most functional languages, I have generally found this statement to be true: if you code looks terse and ugly, there is probably a more elegant solution.
As Toohr points out, a List.map is much more elegant solution.
EDIT: Egads, Toohr beat me to a response. Ignore everything I say.
But normally, a @ b is essentially just:
a' = List.reverse(a), then a loop to :: each element in a' onto b.
...if I am not mistaken, which I may be. Either way, @ is 'slow'.
As for your indenting behavior ... well, I don't use OCaml, but SML is similar enough. As far as it goes, I don't see anything particularly wrong. Personally I just prefer to use 3 spaces so you don't get so much whitespace -- but you have the general idea in my opinion.
With most functional languages, I have generally found this statement to be true: if you code looks terse and ugly, there is probably a more elegant solution.
As Toohr points out, a List.map is much more elegant solution.
EDIT: Egads, Toohr beat me to a response. Ignore everything I say.
:: creates a pair where the first element is the head of the list and the second is the tail, which is a list by itself. That is how lists are built in ml, ie. [1, 2, 3, 4] is actually 1 :: (2 :: (3 :: (4 :: NIL))).
So when you do x :: y the result is the list [x, y1, y2, y3, ..., yn] (x is anything and y is a list) whereas x @ y results in [x1, x2, ..., xn, y1, y2, y3, ..., yn]. The former is constant time O(1) where the later is linear time O(n).
Appending can be implemented by consing (::) all the elements of x on the list of y.
So when you do x :: y the result is the list [x, y1, y2, y3, ..., yn] (x is anything and y is a list) whereas x @ y results in [x1, x2, ..., xn, y1, y2, y3, ..., yn]. The former is constant time O(1) where the later is linear time O(n).
Appending can be implemented by consing (::) all the elements of x on the list of y.
Quote:Original post by visage
But normally, a @ b is essentially just:
a' = List.reverse(a), then a loop to :: each element in a' onto b.
Functionally, in O'Caml, a @ b may be:
let prefix @ l1 l2 = let rec aux = function | [] -> l2 | h::t -> h :: (aux t) in aux l1
It's not guaranteed to be tail-recursive.
An alternative is List.rev_append (List.rev a) b, which is tail-recursive but traverses the list twice.
Last but not least, it would theoretically be possible to implement concatenation as a very fast and constant-space native operation (by creating the list before creating its tail), but I don't think this is done.
Quote:Original post by visageYeah, but it's homework, so I don't get to use library functions whenever.
As Toohr points out, a List.map is much more elegant solution.
Quote:let a x = match x with is equivalent with let a = function, so the second is usually more idiomatic because it's shorter. let a = fun is slightly different in its pattern matching potential (it can pattern-match several arguments at once).
Interesting. I had thought the match with style was preferred because it is clearer the number of arguments required to fully apply the function. The let ... = function style requires that you look either side of the equals sign. On the other hand, I sometimes use the function style because the match with style results in a certain amount of local namespace pollution (i.e. you name something that is rarely used in the function body).
Something I've wondered, is there a concensus on when partially applied functions should be used? I tend too avoid using them to much since, to me at least, they tend to reduce readability (although they can be very useful in some situations). Is this idiomatic Ocaml?
Quote:Original post by Oralloy
Interesting. I had thought the match with style was preferred because it is clearer the number of arguments required to fully apply the function. The let ... = function style requires that you look either side of the equals sign.
The number of arguments is not something very important. First, it's nearly impossible to use an incorrect number of arguments in your program without the compiler complaining (the only ordinary way being, essentially, let _ = foo a at file scope).
What is more important is function semantics, which should be obvious from the function name. If the name isn't enough, then the type and possibly the documentation provide additional information about the semantics. And once you know the semantics, you can't get the argument count or order wrong.
Quote:Something I've wondered, is there a concensus on when partially applied functions should be used? I tend too avoid using them to much since, to me at least, they tend to reduce readability (although they can be very useful in some situations). Is this idiomatic Ocaml?
It's idiomatic to use partially applied functions as arguments to other functions, or as local variables to increase readability. Some people also η-reduce functions to make code shorter, but it's not common except on extremely small and straightforward functions.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement