What's meaning of Pexp_ident use in parsetree.mli? - ocaml

I have this prog parsetreetest.ml:
let ()=
let filename = "test.ml" in
Location.input_name := filename ;
let readhandle = open_in filename in
let buf = Lexing.from_channel readhandle in
Location.init buf filename ;
let ast = Parse.implementation buf in
let pstr_desc=(List.nth ast 0).pstr_desc in
match pstr_desc with
|Pstr_eval (expression,attributes)->
match expression.pexp_desc with
|Pexp_constant constant->
match constant with
|Pconst_integer (const_int,char_option)->
Printf.printf "%s" const_int;
close_in readhandle
If test.ml have only a integer,for example:1,this prog can read it and return Parsetree.
In the parsetree.mli:
and expression_desc =
| Pexp_ident of Longident.t loc
(* x
M.x
*)
| Pexp_constant of constant
(* 1, 'a', "true", 1.0, 1l, 1L, 1n *)
the Pexp_ident is paralleling to Pexp_constant,if I write parsetreetest2.ml:
let ()=
let filename = "test2.ml" in
Location.input_name := filename ;
let readhandle = open_in filename in
let buf = Lexing.from_channel readhandle in
Location.init buf filename ;
let ast = Parse.implementation buf in
let pstr_desc=(List.nth ast 0).pstr_desc in
match pstr_desc with
|Pstr_eval (expression,attributes)->
match expression.pexp_desc with
|Pexp_ident loc->
match loc with
|Lident l->
Printf.printf "%s" l;
close_in readhandle
in test2.ml I write x,as the parsetree.mli example show me,then compiler with ocamlbuild,which used to compile parsetreetest.ml success,got error:
File "parsetreetest2.ml", line 14, characters 7-13:
Error: Unbound constructor Lident
I don't know why I can't do this,thanks!

You don't show a definition for Lident so the obvious conclusion is that the constructor is undefined, which is exactly what the compiler is telling you. The case that works doesn't use Lident, so it doesn't have the error.
It sounds like you're working with some pre-existing files. So the thing to do might be to look around and find the definition of Lident and make sure it is compiled and can be found by the compiler.
If you're copying code from somewhere else, you might look to see whether there are any open declarations in the other code. Possibly an open declaration would make Lident available in your code.

Related

How to alter text using OCaml Containers.CCIO

In the ocaml-containers documentation, it gives a great example, how to read in a file, and write the content to a different file here. However, I am trying to see what it would take to modify the text before it is passed from the file being read to file being written.
let read_filename = "example.ts"
let filename = "example2.ts"
let () =
let modify_file ~chunks =
let r = Str.regexp "text \\([A-Za-z]+\\)" in
Str.replace_first r "\\1" chunks in
CCIO.(
with_in read_filename
(fun ic ->
let chunks = read_chunks ic in
let new_chunks = modify_file chunks in
with_out ~flags:[Open_binary] ~mode:0o644 filename
(fun oc ->
write_gen oc new_chunks
)
)
)
The issue with this code, is that the compiler complains:
File "component.ml", line 13, characters 39-45:
Error: This expression has type string gen = unit -> string option
but an expression was expected of type string
I am trying to figure out what I am doing wrong, but to no avail. Any help would be more than appreciated. Also, suggestions as to the ideal enterprise software to use in OCaml to modify text in files, is more than appreciated. Thank you.
You have a typing problem
read_chunk ic return a string gen value
from here we learn that is a function that take unit value () and return a string.
let () =
CCIO.(
let modify_file ~chunks =
let r = Str.regexp "example \\([A-Za-z]+\\)" in
match chunks () with
None -> chunks (* is the same as (fun () -> None) *)
| Some chunks ->
let chunks = Str.replace_first r "\\1" chunks in (* compute once *)
(fun () -> Some chunks) in
with_in read_filename
(fun ic ->
let chunks = read_chunks ic in
let new_chunks = modify_file ~chunks in
with_out ~flags:[Open_binary] ~mode:0o644 filename
(fun oc ->
write_gen oc new_chunks
)
)
)
EDIT:
explain the error and the change
EDIT 2:
I have modifier modify_file so it return antoher string gen and corrected the syntax error: when you use labeled argument you need to add a tilde when calling it
What is the type of modify_file. I don't see it in the manual.
You should try to add unit value () this way
let new_chunks = modify_file chunks () in and new_chunks will be of type string option
You can pattern match as option type.
EDIT:
I have seen that third parameter has type string gen
You should modify the 16th line this way:
write_gen oc (fun () -> new_chunks)

OCaml Hashtbl/0.t and Hashtbl/-1.t

I am quite new to OCaml, so I am not sure what the following error message means (specifically the /0 and the /-1):
Error: This expression has type (string, string) Hashtbl/0.t
but an expression was expected of type ('a, 'b) Hashtbl/-1.t
I am passing a Hashtbl.t into Hashtbl.find and this error shows up. I am unclear as to how the /0 and /-1 came in, and what they actually mean.
Here's a minimal working example to demonstrate my issue:
open Core_kernel.Std
let file_to_hashtbl filename =
let sexp_to_hashtbl_str = Sexplib.Conv.hashtbl_of_sexp
string_of_sexp string_of_sexp
in In_channel.with_file
filename ~f:(fun ch -> (Sexp.input_sexp ch |> sexp_to_hashtbl_str))
let ht = file_to_hashtbl "test"
let t1_val = match Hashtbl.find ht "t1" with
| Some v -> v
| None -> assert false
let () = print_endline t1_val
Let's show you an example :
If I write
type t = A;;
let x = A;;
type t = B;;
let y = B;;
x = y;;
Error: This expression has type t/1561 but an expression was expected of type
t/1558
This is because in the interpreter you can declare multiple types with the same name and associate values to these types. But here, as you can see, x and y are not of the same type but both the types are named t so the interpreter tries to tell you the types are both named t but are not the same.
[Compilation]
If I wanted to compile this, I would have to declare
typea.ml
type t = A
let x = A
typeb.ml
type t = B
let y = B
main.ml
open Typea
open Typeb
x = y
If I compile this I will have
Error: This expression has type Typeb.t
but an expression was expected of type Typea.t
What lesson should you learn from this ? Stop interpreting, compile !
Now that I managed to compile your file, I got an error too but much more explicit :
Error: This expression has type (string, string) Hashtbl.t
but an expression was expected of type
('a, 'b) Core_kernel.Std.Hashtbl.t =
('a, 'b) Core_kernel.Core_hashtbl.t
[Explanation and correction]
Since I'm too nice, here is your file corrected :
let file_to_hashtbl filename =
(* open the namespace only where needed *)
let open Core_kernel.Std in
let sexp_to_hashtbl_str = Sexplib.Conv.hashtbl_of_sexp
string_of_sexp string_of_sexp
in In_channel.with_file
filename ~f:(fun ch -> (Sexp.input_sexp ch |> sexp_to_hashtbl_str));;
let ht = file_to_hashtbl "test"
let t1_val =
try
Hashtbl.find ht "t1"
with Not_found -> assert false
let () = print_endline t1_val
Your error was that you opened Core_kernel.Std as a global namespace so when you wrote Hashtbl.find it looked first in Core_kernel.Std and not in the standard library.
What I did is open Core_kernel.Std in the function that needs it, not in the whole file (so it's a local namespace) (a good habit to take).
So, as you can see, the problem was that you had two definition of the type Hashtbl.t (one in Core_kernel.Std and one in the standard library) and OCaml ain't no fool, boy, he knows when you're wrong but he is hard to understand since he only speak for those who can hear. :-D
P.S. : You had an error in your Hashtbl.find because it doesn't return an option but the found value or raise a Not_found exception if no value was found. I corrected it too. ;-)
Apparently, it is just a matter of missing semi-columns, the foloowing code compiles :
open Core_kernel.Std;;
let file_to_hashtbl filename =
let sexp_to_hashtbl_str = Sexplib.Conv.hashtbl_of_sexp
string_of_sexp string_of_sexp
in In_channel.with_file
filename ~f:(fun ch -> (Sexp.input_sexp ch |> sexp_to_hashtbl_str));;
let ht = file_to_hashtbl "test"
let t1_val = match Hashtbl.find ht "t1" with
| Some v -> v
| None -> assert false
let () = print_endline t1_val
But, I do not know how to interpret the error message neither.

OCaml error: wrong type of expression in constructor

I have a function save that take standard input, which is used individually like this:
./try < input.txt (* save function is in try file *)
input.txt
2
3
10 29 23
22 14 9
and now i put the function into another file called path.ml which is a part of my interpreter. Now I have a problem in defining the type of Save function and this is because save function has type in_channel, but when i write
type term = Save of in_channel
ocamlc complain about the parameter in the command function.
How can i fix this error? This is the reason why in my last question posted on stackoverflow, I asked for the way to express a variable that accept any type. I understand the answers but actually it doesn't help much in make the code running.
This is my code:
(* Data types *)
open Printf
type term = Print_line_in_file of int*string
| Print of string
| Save of in_channel (* error here *)
;;
let input_line_opt ic =
try Some (input_line ic)
with End_of_file -> None
let nth_line n filename =
let ic = open_in filename in
let rec aux i =
match input_line_opt ic with
| Some line ->
if i = n then begin
close_in ic;
(line)
end else aux (succ i)
| None ->
close_in ic;
failwith "end of file reached"
in
aux 1
(* get all lines *)
let k = ref 1
let first = ref ""
let second = ref ""
let sequence = ref []
let append_item lst a = lst # [a]
let save () =
try
while true do
let line = input_line stdin in
if k = ref 1
then
begin
first := line;
incr k;
end else
if k = ref 2
then
begin
second := line;
incr k;
end else
begin
sequence := append_item !sequence line;
incr k;
end
done;
None
with
End_of_file -> None;;
let rec command term = match term with
| Print (n) -> print_endline n
| Print_line_in_file (n, f) -> print_endline (nth_line n f)
| Save () -> save ()
;;
EDIT
Error in code:
Save of in_channel:
Error: This pattern matches values of type unit
but a pattern was expected which matches values of type in_channel
Save of unit:
Error: This expression has type 'a option
but an expression was expected of type unit
There are many errors in this code, so it's hard to know where to start.
One problem is this: your save function has type unit -> 'a option. So it's not the same type as the other branches of your final match. The fix is straightforward: save should return (), not None. In OCaml these are completely different things.
The immediate problem seems to be that you have Save () in your match, but have declared Save as taking an input channel. Your current code doesn't have any way to pass the input channel to the save function, but if it did, you would want something more like this in your match:
| Save ch -> save ch
Errors like this suggest (to me) that you're not so familiar with OCaml's type system. It would probably save you a lot of trouble if you went through a tutorial of some kind before writing much more code. You can find tutorials at http://ocaml.org.

Passing a string to a C library from OCaml using Ctypes and Foreign

I'm really new to OCaml, and wanted to try and do some work with pcap as a way of getting started, only, there doesn't seem to be a maintained library for it. After looking at the awesome Real World OCaml book, I figured I'd give writing a binding a go.
Here's the (poor) code snippet:
open Ctypes
open Foreign
open PosixTypes
let char_ptr = " "
let pcap_lookupdev = foreign "pcap_lookupdev" (string #-> returning string_opt)
let result = pcap_lookupdev char_ptr
let test2 =
match result with
| None -> char_ptr
| Some str -> str
;;
print_string test2;;
The pcap_lookupdev function returns either a string containing the device name or a null pointer. That bit seems to work fine (although I know my code is hardly idiomatic).
When writing this in C, you need to provide a character array to hold any error messages. So if a null pointer is returned, you should fail with the reason held in this character array. This character array should be "PCAP_ERRBUF_SIZE" long. However I can't figure out two things:
How to pull that constant size from the C library and create a string that size
Pass the string correctly to the function so that it gets correctly populated with the error message
Any help most gratefully appreciated :)
For 1) the easiest way for getting #ifdef'd symbols into OCaml is to write a C program that outputs a seperate module with the value of these symbol. You then just use this module in your bindings when you need the symbols. You can find an example of this approach here.
For 2) I'd say ctypes's string is a little bit deceptive as it doesn't seem to act in a bidirectional fashion, that is you should only use it for const char * or return types. In this case you need to use arrays of character and then translate it to a string (this char_array_as_string function should be added to ctypes I think). Here's the full example, note that in future versions of ctypes the Array module will change its name to CArray:
(* Compile with: ocamlfind ocamlopt -package ctypes.foreign -linkpkg -cclib -lpcap \
-o test.native test.ml *)
open Ctypes;;
open Foreign;;
module Pcap : sig
val lookupdev : unit -> [ `Ok of string | `Error of string ]
end = struct
let errbuf_size = 256 (* N.B. This should not be hardcoded, see 1) above *)
let char_array_as_string a =
let len = Array.length a in
let b = Buffer.create len in
try
for i = 0 to len -1 do
let c = Array.get a i in
if c = '\x00' then raise Exit else Buffer.add_char b c
done;
Buffer.contents b
with Exit -> Buffer.contents b
let lookupdev =
foreign "pcap_lookupdev" (ptr char #-> returning string_opt)
let lookupdev () =
let err = Array.make char ~initial:'\x00' errbuf_size in
match lookupdev (Array.start err) with
| None -> `Error (char_array_as_string err)
| Some dev -> `Ok dev
end
let test () = match Pcap.lookupdev () with
| `Ok dev -> Printf.printf "dev: %s\n" dev
| `Error err -> Printf.printf "error: %s\n" err
let () = test ()

return values from file - ocaml

I am trying to read a file and return the element read from the file as an input to another function.
How can I return a value when I am reading from the file??
I tried everything I am aware of and am still hopelessly lost.
My code is as follows:
let file = "code.txt";;
let oc = open_out file in (* create or truncate file, return channel *)
fprintf oc "%s\n" (play); (* write code to file returned from calling (play) function *)
close_out oc ;;
(*read from file*)
let read l=
let f x =
let ic = open_in file in
let line = input_line ic in (* read line from in_channel and discard \n *)
print_endline line; (* write the result to stdout *)
((x ^ line) :: l);
flush stdout;
close_in ic ;
in
f l
;;
prompt: read;; function call outputs:
- : unit = ()
My file contains a string which is a code needed as input for another function.
Please help. I am not sure where I am going wrong.
Thank you.
If multiple expressions are sequenced together using ; the value of the whole expression is the value of the last expression in the sequence.
So if you have something like ((x ^ line) :: l); close_in ic the value of that expression is the value of close_in ic, which is ().
Obviously that's not what you want. In order to make ((x ^ line) :: l) the result of the whole expression, you should place it after close_in ic.