2017-03-19 2 views
0

Ich bin Student und habe eine Übung erhalten, mit der ich seit ungefähr einem Monat zu kämpfen habe. Ich versuche eine Funktion in Ocaml zu schreiben. Diese Funktion muss eine Textdatei lesen, die ein Wort pro Zeile enthält, und sie muss alle Wörter in einer Liste speichern. Aber das Problem ist, dass dieses Programm eine rekursive sein muss (was bedeutet, keine Schleifen, keine "während").Eine Dateizeile pro Zeile lesen und jede gelesene Zeile in einer einzigen Liste speichern

Alles, was ich habe in der Lage gewesen, so weit zu tun ist, um eine Funktion zu erstellen, die die Textdatei (ziemlich ähnlich wie der BASH Befehl „cat“) Ich weiß es einfach nicht

let dico filename = 
    let f = open_in filename in 
    let rec dico_rec() = 
    try 
     print_string (input_line f); 
     print_newline(); 
     dico_rec(); 
    with End_of_file -> close_in f 
    in dico_rec() ;; 

liest, wie man TU es. Ocaml ist kaum meine Lieblingssprache.

Antwort

0
open Printf 

let file = "example.dat" 

let() = 
    let ic = open_in file in 
    let rec build_list infile = 
      try 
       let line = input_line infile in 
       line :: build_list(infile) 
      with End_of_file -> 
       close_in infile; 
       [] in 
    let rec print_list = function 
      [] ->() 
      | e::l -> print_string e ; print_string " " ; print_list l in 
    print_list(build_list(ic)) 

Edit: Der Algorithmus, den ich zuvor wurde vorgeschlagen unnötig kompliziert. Versuchen Sie stattdessen, dieses zu verstehen.

Um diese Rekursion zu verstehen, gehen wir davon aus, dass build_list korrekt funktioniert. Nehmen wir an, dass build_list eine geöffnete Datei korrekt als Argument akzeptiert und eine Liste von Zeilen in der Datei zurückgibt.

Nun schauen wir uns den Körper der Funktion an. Es liest eine Zeile aus der Datei und ruft erneut build_list auf. Wenn in der Datei N Zeilen vorhanden sind, sollte der Aufruf von build_list erneut eine Liste der verbleibenden N-1 Zeilen in der Datei zurückgeben (da wir gerade die erste Zeile selbst gelesen haben). Wir fügen die Zeile, die wir gerade gelesen haben, an die von build_list zurückgegebene Liste an und geben die resultierende Liste zurück, die alle N Zeilen enthält.

Die Rekursion wird fortgesetzt, bis sie den Basisfall erreicht. Der Basisfall ist, wenn es ein End_of_file gibt. In diesem Fall geben wir eine leere Liste zurück.

+0

Dies funktioniert für kleine Eingabedateien, aber diese Definition von 'build_list' ist nicht tail rekursiv und verursacht einen Stapelüberlauf für große Eingaben. Der "try ... with", der den rekursiven Aufruf umgibt, verhindert, dass es ein Tail-Call ist. –

+0

Guter Ruf ... war eine Weile her, seit ich ocaml benutzt habe :) Denkst du, dass die neue 'build_list' besser ist, oder die alte' (was beinhaltet, dass eine leere Liste als Argument übergeben wird)? Angenommen natürlich, dass ich das 'try ... with' Bit repariere. –

+0

Ich erröte, dies zu OP zuzulassen, der anscheinend kein OCaml-Fan ist, aber man muss lernen, Tail-Calls zu erkennen, wenn man OCaml-Code schreibt. "Versuch ... mit" ist einer der schwierigsten Fälle. –

2

Hier ist eine alternative Definition von build_list, die Tail rekursiv ist. Sie können es anstelle der @ MitchellGouzenko-Definition verwenden, wenn Ihre Eingaben viele Zeilen haben können.

let rec build_list l = 
    match input_line ic with 
    | line -> build_list (line :: l) 
    | exception End_of_file -> close_in ic; List.rev l 
+0

Was macht diese Funktion? – TheScientist

+0

tatsächlich ist die Datei, die ich benutze, ungefähr 500-600 Zeilen lang, also glaube ich nicht, dass es irgendwann einen Stapelüberlauf geben würde – TheScientist

Verwandte Themen