OCaml String Removal and Concatenation - ocaml

The question I have to solve is the following:
Write a function
val newFileName : string -> string -> string;
such that a call (newFileName oldFileName newExtension) returns oldFileName but with the new extension.
For example...
the call (newFileName "MyFileName.java" "class") should return the string "MyFileName.class". The input file name may have zero or more dots.
The call (newFileName "MyFile" "anything") (i.e., with no dots) should return just "MyFile";
The call (newFileName "My.File.java" "class") should return "My.File.class" (i.e., only the rightmost dot matters);
The call (newFileName "MyFile." "class") should return "MyFile.class", i.e., a trailing dot with no actual file extension still gives the new extension.
Hint: Take a look at String.rindex_opt in the standard library.
Here is what I have so far but it's not working:
let newFileName old_file new_class =
match String.rindex_opt old_file '.' with
| None -> old_file
| _ -> let first_part = String.sub old_file 0 (String.rindex old_file '.') in
first_part ^ new_class;;
Is there anything I could do differently?

You could use the value from rindex_opt.
utop #
let replace_extension fn new_ext =
match String.rindex_opt fn '.' with
| None -> fn
| Some ri -> String.sub fn 0 ri ^ "." ^ new_ext;;
val replace_extension : string -> string -> string = <fun>
─( 13:34:57 )─< command 1 >──────────────────────────────────────{ counter: 0 }─
utop # replace_extension "hello.java" "class";;
- : string = "hello.class"
─( 13:36:19 )─< command 2 >──────────────────────────────────────{ counter: 0 }─
utop # replace_extension "hello" "class";;
- : string = "hello"
You might also use Format.sprintf.
utop #
let replace_extension fn new_ext =
match String.rindex_opt fn '.' with
| None -> fn
| Some ri -> Format.sprintf "%s.%s" (String.sub fn 0 ri) new_ext;;
val replace_extension : string -> string -> string = <fun>
─( 13:37:33 )─< command 7 >──────────────────────────────────────{ counter: 0 }─
utop # replace_extension "hello.java" "class";;
- : string = "hello.class"
We might also use a local binding to clean this up a bit further.
let replace_extension fn new_ext =
match String.rindex_opt fn '.' with
| None -> fn
| Some ri ->
let name = String.sub fn 0 ri in
Format.sprintf "%s.%s" name new_ext

It is easily done using the OCaml standard library, namely using the Filename module, e.g.,
let change_extension path ext =
Filename.remove_extension path ^ "." ^ ext

Related

getting error when trying to parse integer

Im trying to run an interpreter I made in ocaml and when i to push in a negative value i.e. let e1 = run [PushI -2; PushI 2; LessThan] []. I am getting a syntax error for my parse_int function. I'm trying to write the part of the function that allows for the input of a negative number
type stackVal =
I of int
type command = PushI of int
let rec run (commands : command list) (stack: stackVal list) : stackVal list =
match (commands , stack) with
| (PushI i :: rest, _ ) -> run rest (I i :: stack)
let to_string (s : stackVal) : string =
match s with
| I i -> string_of_int i
let parse_command (s:string) : command =
match take_while is_alpha (String.trim s) with
| ("PushI" , p) -> let Some i = parse_int (String.trim p) in PushI i
let parse_int (s : string) : int option =
match int_of_string s with
| String.get n 0 = '-' -> Some -String.sub n 1 len
| n -> Some n
| exception _ -> None
There is a problem with the pattern-matching of your parse_int function.
match int_of_string s with
| String.get n 0 = '-' -> Some -String.sub n 1 len
| n -> Some n
| exception _ -> None
The first clause here is invalid as "String.get n 0 = '-'" is not an integer constructor. You could write 1 which matches only the integer 1 or _ whitch matches any integer or n which matches any integer and binds it to the name n for the rest of the clause. You can have a look at the manual for more informations.
If you wanted to check if the first char of the string is - pattern matching is not the right tool to do it, simply use an if then else.
However, note that int_of_string works just fine on negative integers, so there is no need to do that part by yourself.
Unrelated, but i noticed that you call the parse_int in the parse_command function. In that case you should define parse_int before parse_command.

Ocaml cast string to list of tuples

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 ();;

How to access global constructor when you override a variant?

I have this code
module Ignore = struct
type double_asterisk =
| None
| Leading of string
| Trailing of string
| Middle of string * string
let double_asterisk (line:string) : double_asterisk =
let open Re in
let matches pat line =
exec_opt pat line in
let middle = matches ## Perl.compile_pat {|^(.*?)/*\*\*/*(.*?)$|} in
let leading = matches ## Perl.compile_pat {|^\*\*/*(.*)$|} in
let trailing = matches ## Perl.compile_pat {|^(.*?)/*\*\*$|} in
let open Re.Group in
match trailing line with
| Some group -> Trailing (get group 1)
| None -> match leading line with
| Some group -> Leading (get group 1)
| None -> match middle line with
| Some group -> Middle ((get group 1), (get group 2))
| None -> None
let%test _ = double_asterisk "**/foo" = Leading "foo"
let%test _ = double_asterisk "foo/**" = Trailing "foo"
let%test _ = double_asterisk "foo/**/bar" = Middle ("foo", "bar")
let getpath filename =
let open Base in
let open Re.Perl in
let open Re in
match exec_opt (compile_pat {|^(.*)/|}) filename with
| None -> None
| Some g -> Some (Re.Group.get g 1) (* <- ERROR HEERE *)
let%test _ = getpath "foo/bar/tar" = Some "foo/bar"
end
The problem where is that I override the None from Option module with the double_asterisk type. Now the compiler is treating every None as variant of double_asterisk. How can I specify from which type my variant is about?
I'm facing this error
File "git.ml", line 33, characters 20-24:
Error: This variant expression is expected to have type double_asterisk
The constructor Some does not belong to type double_asterisk
Regards
Since 4.08 you can qualify it as Option.None.
In earlier versions you can create a namespaced alias yourself, e.g.:
module MyOption = struct
type 'a t = 'a option = None | Some of 'a
end
let _ = MyOption.None
But I would strongly recommend against overriding the constructors of built-in types. Consider using Nothing or some other equivalent term instead.

OCaml pattern match

in ast.ml, the structure is below:
type beantype =
| Bool
| Int
| TLr of fieldsrec
| TId of ident
and fieldsrec = { fields : field list }
and field =
| FIe of (ident * beantype)
in printer.ml, i use it like below:
let rec print_bean fmt = function
| Bool -> put fmt "%s" "bool"
| Int -> put fmt "%s" "int"
| TLr f -> put fmt "%s" "{"; print_fieldsrec fmt f ; put fmt "%s" "}"
| TId id -> put fmt "%s" id
and print_fieldsrec fmt = function
| f :: fe -> print_field fmt f; put fmt "%s" "," ; print_fieldsrec fmt fe
and print_field fmt = function
| FIe (id, beantype) -> put fmt "%s" id; put fmt "%s" ":"; print_bean fmt beantype
However it said the different pattern match in print_fieldsrec
Error: This pattern matches values of type 'a list
but a pattern was expected which matches values of type
Bean_ast.fieldsrec
how can i change the printer.ml?
You seem to be confused by the type fieldsrec = { fields : field list }. You should have followed Jeffrey's advice of using | Fields of field list instead.
fieldsrec is not a list, it is a record containing a list, so
print_fieldsrec fmt = function f :: fe -> ...
doesn't have the type its name suggests.
Also you forgot the base case for the recursive print_fieldsrec.

Use Async to make an GET request

Taken from the chapter 18 of the Real World OCaml book, I'm trying to break down the example given.
My scope, to just make the GET call and print something of the JSON we get back.
This is my code ( it's supposed to be a subset of the example given )
(* libraries *)
open Core.Std
open Async.Std
(* Generate a DuckDuckGo search URI from a query string *)
let query_uri query =
let base_uri = Uri.of_string "http://api.duckduckgo.com/?format=json" in
Uri.add_query_param base_uri ("q", [query])
(* Extract the "Definition" or "Abstract" field from the DuckDuckGo results *)
let get_definition_from_json json_string =
match Yojson.Safe.from_string json_string with
| `Assoc kv_list ->
let find key =
begin match List.Assoc.find kv_list key with
| None | Some (`String "") -> None
| Some s -> Some (Yojson.Safe.to_string s)
end
in
begin match find "Abstract" with
| Some _ as x -> x
| None -> find "Definition"
end
| _ -> None
(* Execute the DuckDuckGo search *)
let get_definition word =
print_endline ("get_definition word:" ^ word);
Cohttp_async.Client.get (query_uri word)
>>= fun (_, body) ->
Pipe.to_list (Cohttp_async.Body.to_pipe body)
>>| fun strings ->
(word, get_definition_from_json (String.concat strings))
(* run *)
let () =
get_definition "OCaml"
>>= fun (word, def) ->
print_endline ("- word: " ^ word);
(
match def with
| None -> print_endline "[EMPTY]"
| Some str -> print_endline str
)
My issue is that I get this error when compiling:
ocaml setup.ml -build
Finished, 0 targets (0 cached) in 00:00:00.
+ /Users/antouank/.opam/system/bin/ocamlfind ocamlc -c -g -annot -bin-annot -thread -package yojson -package threads -package textwrap -package re2 -package core -package cohttp.async -I src -o src/main.cmo src/main.ml
File "src/main.ml", line 48, characters 18-41:
Error: This expression has type unit but an expression was expected of type
'a Async.Std.Deferred.t = 'a Async_kernel.Deferred0.t
Command exited with code 2.
Compilation unsuccessful after building 2 targets (0 cached) in 00:00:00.
E: Failure("Command ''/usr/local/bin/ocamlbuild' src/main.native -use-ocamlfind -tag debug' terminated with error code 10")
make: *** [build] Error 1
How can I get the string out of that Deferred, and what does that error mean exactly?
In the book, the example is run with a weird Command wrap, so I cannot see how to pull it out.
The problem in your definition of run is that the anonymous function
fun (word, def) ->
print_endline ("- word: " ^ word);
(
match def with
| None -> print_endline "[EMPTY]"
| Some str -> print_endline str
)
is not correctly typed to be used with a monadic operator >>=. It has type string * string -> unit while the >>= would here expect a function of type string * string -> unit Deferred.t.
If you look at the example of an echo server in the very same chapter, it will suggest the following approach:
let run () =
get_definition "OCaml"
>>= fun (word, def) ->
print_endline ("- word: " ^ word);
(
match def with
| None -> print_endline "[EMPTY]"
| Some str -> print_endline str
);
Deferred.return()
let () =
ignore(run ());
never_returns (Scheduler.go ())