Understanding Text IO - sml

My function is trying to read a textfile line by line and carry out a certain predefined function on each line called somefn and append the value of somefn to the function. The somefn is already defined above this and works fine.
fun extractline(infile:string)=
let
val insl=TextIO.inputLine(ins)
case insl of
NONE=> []
|SOME(l)=>somefn(insl)::extractline(infile)
in
TextIO.closeIn(ins);
end
;
I am having errors and cannot handle them.
I would appreciate some help.
Thank You.

Remember, in let ... in ... end blocks, you place declarations you need between let and i n, and the resulting expression between in and end.
As such, you need your case expression placed between in and end.
You also never open the stream, ins. Make your function open the stream, and then work recursively on that stream in another function, however; you don't want to open the file for each recursive call.
You'll want something on this form:
fun extractline file =
let
val ins = TextIO.openIn file
fun extractline_h () = (* do something with ins here *)
in
extractline_h () before
TextIO.closeIn ins
end
Then you make extractline_h be recursive, and build up the list in that.

Related

Have Trouble Understanding OCaml Code

I need to modify an OCaml function:
let removeDuplicates l =
let rec helper (seen,rest) =
match rest with
[] -> seen
| h::t ->
let seen' = failwith "to be written" in
let rest' = failwith "to be written" in
helper (seen',rest')
in
List.rev (helper ([],l));;
The function needs to take a list l and return the list with all duplicates removed. The failwith "to be written" parts is where I'm supposed to write my code. I understand how the helper function works but am having trouble understanding this part helper (seen',rest'). I'm not exactly sure how the function is supposed to flow with this part or how it works when you include a bunch of in's all together. We are allowed to use List.rev which reverses a list and list.mem which returns true if a certain element is in a list. Can someone please explain to me how the flow of the function is supposed to work so I can start to write a solution.
That line is confusing because it's indented incorrectly, or so I would claim. The proper indentation looks like this:
let seen' = failwith "to be written" in
let rest' = failwith "to be written" in
helper (seen',rest')
What it's saying is: calculate a new value for seen and a new value for rest, then call yourself recursively with the two new values.

Functions and Files

please help :)
I'm learning from pythonhardway
Exercise 20:Functions and Files
from sys import argv
script, input_file = argv
def print_all(f):
print f.read()
def rewind(f):
f.seek(0)
def print_a_line(line_count, f):
print line_count, f.readline()
current_file = open(input_file)
print "First let's print the whole file:\n"
print_all(current_file)
print "Now let's rewind, kind of like a tape."
rewind(current_file)
print "Let's print three lines:"
current_line = 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
current_line = current_line + 1
print_a_line(current_line, current_file)
if current line = 2
it print the second line how ???!!!!!!!
def rewind(f):
f.seek(0)
& **rewind(current_file)**
why we put (f)
why not input_file ?!
i tried to explain what i think it is doing.
Sorry if i ask stupid questions :(
There are two issues at work here.
1 -- difference between name of file and file object you can operate on
2 -- difference between parameter names in functions and values used to call those functions
When you have a file named (e.g.) data.csv, you can refer to it using a string:
file_name = 'data.csv'
... but that's just a string of characters. To operate on the file with that name, you do:
fh = open(file_name)
You now have a file handle that can be used with file read, write, delete, seek etc. functions. So the first part of your answer is, file names are not the same things as file objects; so you would call the rewind function using current_file (the file handle) not input_file (the file name).
The other issue, perhaps obvious, is the placeholder parameter you use to define a function (like f in your example) is just a placeholder -- when you call that function later, the value you call it with is used.
So while the function is defined as rewind(f), when you call it later as rewind(current_file) you are in fact performing a seek on current_file -- not f, that's just a placeholder.
So in short -- you call seek (inside the function definition) using f because that's the placeholder / symbol name you chose to use for your reusable function (and that name could be changed to almost anything you want, in the function definition and function body) without affecting anything. And the reason you call rewind using current_file is that is the file object you opened to work on.
Does it make sense?

How to print into file in OCaml in a appending way?

Currently I have some code in this way:
method printFuncIntoFile X =
let funHead = "head"
and funbody = "body"
and oc = open_out "test.txt" in
Printf.fprintf oc "%s%s" funHead funBody;
close_out oc;
foo X.child
And this code can only leave the last function content in the text.txt.
I search the Printf document but can only find a
val bprintf : Buffer.t -> ('a, Buffer.t, unit) format -> 'a
which requires a Buffer data structure, I think there should be some strategies more easy, even though I don't know
So my question is that:
How to print into file in OCaml in a appending way?
You should be able to use:
open_out_gen [Open_append; Open_creat] 0o666 "test.txt"
Note that opening channels isn't part of Printf, but part of the Pervasives module.

OCaml - Creating a function which prompts for floats and returns a list of floats

I'm teaching myself OCaml and I sometimes need to create a function where I'm not really sure what the proper solution should be. Here's one that I'm a little confused about.
I need a function that will prompt the user for individual float values and return everything entered in a float list. I can create this function but I'm not sure if its the proper/best way to do it in Ocaml.
Here's my attempt.
let rec get_floats() =
match
(
try Some(read_float())
with
| float_of_string -> None
)
with
| None -> []
| Some s -> s :: get_floats();;
This code works buts I'm at a loss deciding if its a 'proper OCaml' solution. Note, to exit the function and return the float list just enter a non-integer value.
(I hope that) this is a simple peephole rewrite involving no thought whatsoever of the function in your question:
let rec get_floats() =
try
let f = read_float() in (* as suggested by Martin Jambon *)
f :: (get_floats())
with
| float_of_string -> []
The idea I tried to apply here is that you do not need to convert the success/failure of read_float into an option that you immediately match: just do what you have to do with the value read, and let the with handle the failure case.
Now that I think of it, I should point out that in both your question and my rewrite, float_of_string is a fresh variable. If you meant to match a specific exception, you failed at it: all exception constructors, like datatype constructors, are Capitalized. You might as well have written with _ -> instead of with float_of_string ->, and a recent version of OCaml with all warnings active should tell you that your function (or mine) binds a variable float_of_string without ever using it.
Thanks everyone for the help. This works.
let rec get_floats() =
try
let x = read_float() in
x :: get_floats()
with
| _ -> [];;
List.iter (fun x -> print_endline(string_of_float x)) (get_floats());;

how to generate a list quickly iterating a file

Me coming from a c# and python background, feels there must be a better way to read a file and populate a classic F# list. But then I know that a f# list is immutable. There must be an alternative using a List<string> object and calling its Add method.
So far what I have at hand:
let ptr = new StreamReader("stop-words.txt")
let lst = new List<string>()
let ProcessLine line =
match line with
| null -> false
| s ->
lst.Add(s)
true
while ProcessLine (ptr.ReadLine()) do ()
If I were to write the similar stuff in python I'd do something like:
[x[:-1] for x in open('stop-words.txt')]
Simple solution
System.IO.File.ReadAllLines(filename) |> List.ofArray
Although you can write a recursive function
let processline fname =
let file = new System.IO.StreamReader("stop-words.txt")
let rec dowork() =
match file.ReadLine() with
|null -> []
|t -> t::(dowork())
dowork()
If you want to read all lines from a file, you can just use ReadAllLines. The method returns the data as an array, but you can easily turn that into F# list using List.ofArray or process it using the functions in the Seq module:
open System.IO
File.ReadAllLines("stop-words.txt")
Alternatively, if you do not want to read all the contents into memory, you can use File.ReadLines which reads the lines lazily.