简体   繁体   中英

OCaml. Return first n elements of a list

I am new to OCaml and functional programming as a whole. I am working on a part of an assignment where I must simply return the first n elements of a list. I am not allowed to use List.Length.

I feel that what I have written is probably overly complicated for what I'm trying to accomplish. What my code attempts to do is concatenate the front of the list to the end until n is decremented to 1. At which point the head moves a further n-1 spots to that the tail of the list and then return the tail. Again, I realize that there is probably a much simpler way to do this, but I am stumped and probably showing my inability to grasp functional programming.

   let rec take n l =
        let stopNum = 0 - (n - 1) in
        let rec subList n lst =
        match lst with
        | hd::tl -> if n = stopNum then (tl)
                        else if (0 - n) = 0 then (subList (n - 1 ) tl )
                        else subList (n - 1) (tl @ [hd])
        | [] -> [] ;;

My compiler tells me that I have a syntax error on the last line. I get the same result regardless of whether "| [] -> []" is the last line or the one above it. The syntax error does not exist when I take out the nested subList let. Clearly there is something about nested lets that I am just not understanding.

Thanks.

Since you're just starting with FP, I suggest you look for the simplest and most elegant solution. What you're looking for is a way to solve the problem for n by building it up from a solution for a smaller problem.

So the key question is: how could you produce the first n elements of your list if you already had a function that could produce the first (n - 1) elements of a list?

Then you need to solve the "base" cases, the cases that are so simple that the answer is obvious. For this problem I'd say there are two base cases: when n is 0, the answer is obvious; when the list is empty, the answer is obvious.

If you work this through you get a fairly elegant definition.

let rec firstk k xs = match xs with
| [] -> failwith "firstk"
| x::xs -> if k=1 then [x] else x::firstk (k-1) xs;;

You might have been looking for this one.

What you have to do here, is to iterate on your initial list l and then add elements of this list in an accumulator until n is 0.

let take n l =
  let rec sub_list n accu l =
    match l with 
    | [] -> accu (* here the list is now empty, return the partial result *)
    | hd :: tl ->
      if n = 0 then accu (* if you reach your limit, return your result *)
      else (* make the call to the recursive sub_list function:
                 - decrement n, 
                 - add hd to the accumulator,
                 - call with the rest of the list (tl)*) 
  in
  sub_list n [] l

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM