2012-03-20 16 views
7

Jestem nowym użytkownikiem Ocaml, ale chcę się upewnić, jak wykonać prostą funkcję, taką jak powrót n-tego elementu listy za pomocą funkcji rekursywnej?zwraca n-ty element listy w OCaml?

Prototype jak get_nth (list, n) z int list * int -> int

np get_nth ([1,2,3], 1) -> 2

Dziękuję

+1

To naprawdę brzmi jak zadanie domowe. Pomogłoby to, gdybyś pokazał kod, który wypróbowałeś, a który nie działa tak, jak ci się wydawało. –

Odpowiedz

11

Możesz nie zauważyć, ale funkcja List.nth jest już dostępna w .

Jeśli chcesz napisać go za pomocą rekurencji:

let rec get_nth = function 
    | [], _ -> raise (Failure "get_nth") 
    | _, n when n < 0 -> raise (Invalid_argument "get_nth") 
    | x::_, 0 -> x 
    | x::xs, n -> get_nth(xs, n-1) 
+0

@VictorNicollet: Dzięki za edycję. – pad

4

Korzystanie krotki jako parametry, jak to nie jest powszechne w SML. Zwykle byłoby użyć currying i określić swoją funkcję tak:

let get_nth list n = ... 

Miałoby to podpis 'a list -> int -> 'a. Zauważ też, że masz tutaj pewien parametr 'a, co oznacza, że ​​nie ma prawdziwego powodu, aby ograniczać swoją funkcję do samych int.

Teraz spójrzmy na problem. Jeśli chcesz uzyskać element zerowy, jak powinna wyglądać twoja funkcja?

let get_nth list 0 = List.head list (* this is not actually valid in OCaml *) 

teraz jeśli masz funkcji, aby uzyskać n-ty element z listy elementów M (NB n> m), w jaki sposób można wykorzystać tę funkcję, aby zbudować inną funkcję, które uzyskać to n + 1-ej od A lista elementów m + 1? Pozwól, że funkcja n + 1 pierwiastków być get_nth'

let get_nth' list n' = get_nth (List.tail list) (n'-1) 

Teraz wszystko, co musisz zrobić, to połączyć dwa i gotowe. Zostawię ci ostatnią część.

Jeśli zastosujesz się do tej porady, otrzymasz coś, co jest bardziej skomplikowane, niż musi być. Jednak łatwiej jest zrozumieć, co dzieje się w ten sposób.

+0

Niestety, obawiam się, że twoja próba jest bardziej zagmatwana, niż powinna. Dopasowanie do wzoru Ocaml jest dość wizualnie wyjaśniające. – PieOhPah

3

(moim zdaniem) Prostsze rozwiązanie bez użycia krotki mogą być:

let rec get_nth mylist index = match mylist with 
    | [] -> raise (Failure "empty list") 
    | first::rest -> 
     if index = 0 then first 
     else get_nth rest (index-1) 
;; 
+1

Uczyniłbym tę poprawną odpowiedź. Używanie krotki jako argumentu w funkcji Ocaml nie jest bardzo idiomatyczne i wymaga przydziału. – PieOhPah

0

Czytałem here że używanie Result zamiast podnosić błąd może być przyjemniej, ponieważ nie musisz używać try ... with. (Kod edytowane z @Omar Mahili)

let rec get_nth mylist index = match mylist with 
    | [] -> Error "empty list" 
    | first::rest -> 
     if index = 0 then Ok first 
     else get_nth rest (index-1) 
;; 

let result [1; 2; 3] 2 in 
    match result with 
    | Error reason -> print_string reason 
    | Ok num -> print_int num 
;; 

Result jest częścią Core.Std, jeśli się nie mylę.

Powiązane problemy