I have the file "example.dat" with text "[(1,2); (3,4); (5,6)]". I need to get list of tuples from it. I know, how I can get it from list of ints.
# let f line = List.map int_of_string line;;
# open Printf
let file = "example.dat"
let () =
let ic = open_in file in
try
let line = input_line ic in
f line;
flush stdout;
close_in ic
with e ->
close_in_noerr ic;
raise e;;
How I must to change my functions?
Given a list of strings that represent ints, your function f returns a list of ints. It doesn't return a list of tuples.
You don't say whether you want to verify that the input has some kind of proper form. If you want to verify that it has the form of (say) a list of type (int * int) list in OCaml, this is a parsing problem that would take some work.
If you just want to extract the parts of the input line that look like ints, you can use regular expression processing from the Str module:
# let re = Str.regexp "[^0-9]+" in
Str.split re "[(1,2); (37,4); (5,6)]";;
- : string list = ["1"; "2"; "37"; "4"; "5"; "6"]
Then you can rewrite your function f to collect up each pair of ints into a tuple. I don't see a good way to use List.map for this. You might have to write your own recursive function or use List.fold_left.
Update
I will write you a function that changes a list of values into a list of pairs. I hope this isn't for a school assignment, in which case you should be figuring this out for yourself.
let rec mkpairs l =
match l with
| [] | [_] -> []
| a :: b :: rest -> (a, b) :: mkpairs rest
As you can see, this function silently discards the last element of the list if the list has an odd number of elements.
This function is not tail recursive. So that's something you could think about improving.
let open Genlex in
let open Stream in
let lexer = make_lexer ["["; "("; ","; ")"; ";"; "]";] in
let stream = lexer (of_string array_string) in
let fail () = failwith "Malformed string" in
let parse_tuple acc = match next stream with
| Int first -> ( match next stream with
| Kwd "," -> ( match next stream with
| Int second -> ( match next stream with
| Kwd ")" -> (first, second) :: acc
| _ -> fail () )
| _ -> fail () )
| _ -> fail () )
| _ -> fail ()
in
let rec parse_array acc =
match next stream with
| Kwd "(" -> parse_array (parse_tuple acc)
| Kwd ";" -> parse_array acc
| Kwd "]" -> acc
| _ -> fail ()
in
try
match next stream with
| Kwd "[" -> List.rev (parse_array [])
| _ -> fail ()
with Stream.Failure -> fail ();;
Related
I have a question about how Seq's unfold function is implemented.
I tried creating my own Seq module(My_Seq) to see if I understood how that functionality worked and I can't get my unfold to behave like Seq's unfold function.
Here's my attempt(My_Seq, note I removed all but the necessary functionality)
module type My_Seq_Sig =
sig
type 'a t
val empty: 'a t
val iter: ('a -> unit) -> 'a t -> unit
val unfold : ('b -> ('a * 'b) option) -> 'b -> 'a t
end
module My_Seq:My_Seq_Sig =
struct
type 'a t = unit -> 'a node
and
'a node =
| Nil
| Cons of 'a * 'a t
let empty = fun () -> Nil
let rec iter f s =
match s() with
| Nil -> ()
| Cons (e, next) -> f e; iter f next
let rec unfold f e =
match (f e) with
| None -> empty
| Some (e, next) -> fun () -> Cons (e, unfold f next)
end
Here's how I'm calling my module My_Seq:
let seq =
let line = ref 0 in
let filename = print_string "Enter filename: "; read_line() in
My_Seq.unfold
(
fun e ->
try
line := !line + 1;
Some(((string_of_int !line) ^ ": " ^ (input_line e)), e)
with
End_of_file
| _ ->
print_endline("---Read->" ^ string_of_int (!line - 1) ^ "<-Line(s)---");
close_in e;
None
)
(open_in filename)
let () =
seq |> My_Seq.iter print_endline
Here's the output from my attempt:
Enter filename: datafile
1: This is the first
2: This is the second
3: This is the third
4: This is the fourth
---Read->5<-Line(s)---
5: This is the fifth
Now if I use Seq's unfold function:
let seq2 =
let line = ref 0 in
let filename = print_string "Enter filename: "; read_line() in
Seq.unfold
(
fun e ->
try
line := !line + 1;
Some(((string_of_int !line) ^ ": " ^ (input_line e)), e)
with
End_of_file
| _ ->
print_endline("---Read->" ^ string_of_int (!line - 1) ^ "<-Line(s)---");
close_in e;
None
)
(open_in filename)
let () =
seq2 |> Seq.iter print_endline
Here's the output from using Seq's unfold function:
Enter filename: datafile
1: This is the first
2: This is the second
3: This is the third
4: This is the fourth
5: This is the fifth
---Read->5<-Line(s)---
datafile contents:
This is the first
This is the second
This is the third
This is the fourth
This is the fifth
You'll note that the outputs differ and I have no idea why. Maybe someone can shed some light on this.
That did it Guest0x0
let rec unfold f e =
fun () ->(
match (f e) with
| None -> Nil
| Some (e, next) -> Cons (e, unfold f next))
The difference lies in when the last element is computed. In your unfold, the last element is computed (in f e) when the element before it is fetched (via feeding a unit argument somewhere), while the Stdlib version computes the last element only when that element itself is fetched.
To make your unfold behaves like the Stdlib one, notice that both branches of your unfold returns a function taking unit as argument. By lifting this argument outside the whole pattern matching, the actual computation of f e will then get delayed, leading to the Stdlib behavior
I must use the following data type:
type ilist = E | L of int * ilist
I can't seem to find much help on working with lists outside of the standard type online ( [1;2;3] )
I am to write a function that takes a lists and reverses the order
for example: reverse (L(1, L(2, L(3, E)))) would output (L(3, L(2, L(1, E))))
So far here is my code:
let rec reverse l =
match l with
| E -> failwith "Empty List"
| L(h, E) -> h
| L(h, t) -> // append tail and recursive call with rest of list?
let list = reverse (L(1, L(2, L(3, E))))
printfn "reversed list: %A" list
Thanks for any help!
What you are lacking is a convenient way to append an int to an ilist:
let rec append x l =
match l with
| E -> L (x,E)
| L (h,t) -> L (h,append x t)
printfn "%A" (append 4 list)
Now use this function in your last match case to append h to the reversed t:
let rec reverse l =
match l with
| E -> E
| L (h,t) -> append h (reverse t)
Note that it's probably better to just return an empty list when the input list is empty (| E -> E), because failwith is something very ugly you should only use in the rarest cases.
Also note that your second match case | L(h, E) -> h is wrong, because it returns an int instead of an ilist. But it is not needed anyway, so just remove it. The singleton list L (h,E) will be matched with | L (h,t) -> ... instead, which in turn recursively matches t with | E -> E.
Here is a working example: https://repl.it/repls/PhonyAdventurousNet
I'm trying to use the CIL library to parse C source code. I'm searching for a particular function using its name.
let cil_func = Caml.List.find (fun g ->
match g with
| GFun(f,_) when (equal f.svar.vname func) -> true
| _ -> false
) cil_file.globals in
let body g = match g with GFun(f,_) -> f.sbody in
dumpBlock defaultCilPrinter stdout 1 (body cil_func)
So I have a type GFun of fundec * location, and I'm trying to get the sbody attribute of fundec.
It seems redundant to do a second pattern match, not to mention, the compiler complains that it's not exhaustive. Is there a better way of doing this?
You can define your own function that returns just the fundec:
let rec find_fundec fname = function
| [] -> raise Not_found
| GFun (f, _) :: _ when equal (f.svar.vname fname) -> f (* ? *)
| _ :: t -> find_fundec fname t
Then your code looks more like this:
let cil_fundec = find_fundec func cil_file.globals in
dumpBlock defaultCilPrinter stdout 1 cil_fundec.sbody
For what it's worth, the line marked (* ? *) looks wrong to me. I don't see why f.svar.vname would be a function. I'm just copying your code there.
Update
Fixed an error (one I often make), sorry.
I can't wrap my head around where should I put parenthesis to get it working:
let read_lines filename =
let channel = open_in filename in
Std.input_list channel;;
let print_lines filename =
List.map print_string ((^) "\n") (read_lines filename);;
^ This is the closes I've got so far. If my terminology is vague: ((^) "\n") is what I call partial function (well, because it doesn't handle all of its arguments). print_string I call total function because... well, it handles all of its arguments.
Obviously, what I would like to happen is that:
List.map applies first ((^) "\n") to the element of the list.
List.map applies print_string to the result of #1.
How? :)
Maybe you want something like that?
# let ($) f g = fun x -> f(g x);;
val ( $ ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
# let f = print_string $ (fun s -> s^"\n");;
val f : string -> unit = <fun>
# List.iter f ["a";"b";"c";"d"];;
a
b
c
d
- : unit = ()
# let g = string_of_int $ ((+)1) $ int_of_string;;
val g : string -> string = <fun>
# g "1";;
- : string = "2"
Your code didn't work because missing parenthesis:
List.map print_string ((^) "\n") xs
is parsed as
(List.map print_string ((^) "\n")) xs
when you expected
List.map (print_string ((^) "\n")) xs
A few things: List.map is probably not what you want, since it will produce a list (of unit values) rather than just iterating. ((^) "\n") is probably also not what you want, as it prepends a newline, the "\n" being the first argument. (This is not a section as in Haskell, but a straightforward partial application.)
Here's a reasonable solution that is close to what (I think) you want:
let print_lines filename =
List.iter (fun str -> print_string (str ^ "\n")) (read_lines filename)
But I would rather write
let print_lines filename =
List.iter (Printf.printf "%s\n") (read_lines filename)
Which is both clearer and more efficient.
I'm new at OCaml (and still a novice in learning programming in general) and I have a quick question about checking what kind of string the next element in the string list is.
I want it to put a separator between each element of the string (except for the last one), but I can't figure out how to make the program 'know' that the last element is the last element.
Here is my code as it is now:
let rec join (separator: string) (l : string list) : string =
begin match l with
| []->""
| head::head2::list-> if head2=[] then head^(join separator list) else head^separator^(join separator list)
end
let test () : bool =
(join "," ["a";"b";"c"]) = "a,b,c"
;; run_test "test_join1" test
Thanks in advance!
You're almost there. The idea is breaking down the list in three cases where it has 0, 1 or at least 2 elements. When the list has more than one element, you're safe to insert separator into the output string:
let rec join (separator: string) (l : string list) : string =
begin match l with
| [] -> ""
| head::[] -> head
| head::list-> head^separator^(join separator list)
end
I have several comments about your function:
Type annotation is redundant. Because (^) is string concatenation operator, the type checker can infer types of separator, l and the output of the function easily.
No need to use begin/and pair. Since you have only one level of pattern matching, there is no confusion to the compiler.
You could use function to eliminate match l with part.
Therefore, your code could be shortened as:
let rec join sep l =
match l with
| [] -> ""
| x::[] -> x
| x::xs -> x ^ sep ^ join sep xs
or even more concise:
let rec join sep = function
| [] -> ""
| x::[] -> x
| x::xs -> x ^ sep ^ join sep xs
The empty list is [], the list with one element is [h] and the list with at least one element is h::t. So your function can be written as:
let rec join separator = function
| [] -> ""
| [h] -> h
| h::t -> h ^ separator ^ join separator t