Reputation: 3106
I'm just learning OCaml and right now, I use match l with h::t ->
to split lists when I need to access the head. But I'm sure there has to be a better way to split a list this way. I can't seem to find much online. Maybe I'm not looking in the right way.
Upvotes: 4
Views: 9919
Reputation: 1172
The OCaml way for this issue is the expression
match l with
| [] -> some_expr
| x :: xs -> some_other_expr
The worst solution is using List.hd
or List.hd
, leading to possible runtime exception.
The second worse solution is an incomplete match such as match l with x :: xs
leading also to the same runtime errors, but you at least get a compile time warning, with the matching case(s) you missed.
Note that you can ignore some parts of the matching if not used, so your code is self documenting:
let hd_option lst =
match lst with
| [] -> None
| x :: _ -> Some x (* the tail is not used, so I just don't name it *)
Upvotes: 1
Reputation: 48581
I don't know OCaml, but Haskell offers these, which you can probably translate easily:
-- I think ML might write this signature
-- uncons : 'a list -> ('a * 'a list) option
uncons :: [a] -> Maybe (a, [a])
uncons (x : xs) = Just (x, xs)
uncons [] = Nothing
maybe :: b -> (a -> b) -> Maybe a -> b
maybe def f Nothing = def
maybe def f (Just x) = f x
Then you can write things like
drop1 :: [a] -> [a]
drop1 = maybe [] snd . uncons
Upvotes: -2
Reputation: 9030
It's the best way.
There are functions List.hd
and List.tl
to get hd
and tl
but there is no function available in the standard library to get the head and tail in one move. In addition List.hd
and List.tl
are unsafe: if you give an empty list to them, they raise runtime exceptions:
# List.hd [];;
Exception: Failure "hd".
You can use them safely if you are 100% sure that the argument cannot be empty, but your speculation is often not correct in practice. List.hd
and tl
can be very good sources of bugs.
Using patterns with let
: let (h::t) = l in ...
is possible, but it also has a risk of runtime failures, but the compiler can tell you that your pattern is not exhaustive and lacks the handling of []
.
match
can have multiple cases and you can cover the case for []
: match l with [] -> ... | (h::t) -> ...
. If you forget the case for []
, the compiler can warn you about it.
Upvotes: 8