2016-04-20 17 views
5

Chcę odczytać niektóre numery z pliku, przenieść je do listy i wyświetlić je na ekranie. numbers.txt ma obecnie numer 2 3 5 7 11, jednak jako wynik uzyskuję 11 7 5 3 2 - : unit =()funkcja zwraca listę w odwrotnej kolejności w OCaml

Dlaczego tak się dzieje?

let rec int_list_from_sb sb n = 
match n with 
| 0 -> []; 
| _ -> (bscanf sb " %d" (fun a -> a))::(int_list_from_sb sb (n - 1));; 

let file_name = open_in "numbers.txt" in 
let sb = Scanning.from_channel file_name in 
let int_list = int_list_from_sb sb 5 in 
List.iter (fun a -> print_int a) int_list;; 

Odpowiedz

5

Kolejność oceny argumentów jest nieokreślona w OCaml. Więc kiedy robisz f x :: g y, nie jest określone, czy f lub g zostanie wywołany jako pierwszy. W twoim przypadku wywołanie rekursywne jest wywoływane przed wywołaniem bscanf, dlatego otrzymujesz wyniki w niewłaściwej kolejności.

Ogólnym sposobem naprawienia problemów z oceną jest umieszczenie argumentów funkcji w zmiennych lokalnych, gdy kolejność ich efektów ubocznych ma znaczenie. Więc zamiast f x :: g y, możesz zrobić let fx = f x in fx :: g y, jeśli chcesz, aby efekty f x zdarzyły się przed wywołaniem g.

Jednak w twoim przypadku można po prostu skorzystać z kontynuacji argumentu bscanf jest tak:

bscanf sb " %d" (fun a -> a :: int_list_from_sb sb (n - 1)) 
+0

jeśli wybierze drugą funkcję Tutaj rekurencyjną jeden, co dzieje się z całkowitą że bscanf uzyskanego? –

+0

@power_output Co się dzieje, że 'int_list_from_sb 4' ocenia, czytając 4 numery z' sb' i zwracając '[7; 5; 3; 2] ', następnie' bscanf sb "% d" (fun a -> a) 'ocenia i zwraca' 11', a następnie '11 :: [7; 5; 3; 2] 'jest obliczane i zwraca' [11; 7; 5; 3; 2] '. – sepp2k

+0

@power_output Masz szczęście, ponieważ system właśnie odłożył skanowanie w przewidywalny sposób. Wyniki mogą (* w zasadzie *) być jeszcze bardziej interesujące, ponieważ 'sb' jest zmienną strukturą: wyobraź sobie, co by się stało, gdyby oba wyrażenia zostały ocenione, na przykład, z kolei. –

Powiązane problemy