operator (-): string → string → string that subtracts the letters in a string from the letters in another string, e.g., "Walcw Cacdsa"-"abcwxyz" will give "Wlw Cds" note that the operator - is case sensitive
I try with this code but don't work and tell me Syntax error.
let sub str =
for i = 0 to String.length str - 1 do
let string = Char.escaped str.[i] in
if string = "c" then str.replace(string, " ")
else let s3 = s3^string
done;;
Strings are an interesting thing to work with in OCaml. They're immutable meaning we have to create a new string rather than modifying the one passed in, but not readily pattern-matched. There are regular expressions, which make this kind of problem trivial, but it would be a lot easier if we had a list or sequence of characters, instead of a string.
Imagine if we had a list of integers and wanted to remove the integers in a second list from it using sequences.
let remove_ints lst lst_to_remove =
lst
|> List.to_seq
|> Seq.filter
(fun x ->
lst_to_remove
|> List.to_seq
|> Seq.exists ((=) x)
|> not)
|> List.of_seq
Here the list is converted to a sequence, then filtered based on that int not appearing in a sequence created from the list of ints to remove. Finally, that filtered sequence is converted back into a list.
If I want to make this an operator (using - is a bad idea in practice but we'll use it for now), you can easily do that.
let (-) = remove_ints
utop # [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] - [5; 6; 2];;
- : int list = [1; 3; 4; 7; 8; 9; 10]
This same logic can be applied to removing all of the characters in a string from another string. You simply need to convert a string to and from a sequence.
Related
My goal is to take a char list like:
['a'; 'a'; 'a'; 'a'; 'a'; 'b'; 'b'; 'b'; 'a'; 'd'; 'd'; 'd'; 'd']
Count the number of repeated characters and transform it into a (int * char) list like this:
[(5, 'a'); (3, 'b'); (1, 'a'); (4, 'd')]
I am completely lost and also am very very new to OCaml. Here is the code I have rn:
let to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
let count = int 0 in
while t <> [] do
if h = t then
count := count + 1;
done;
I am struggling on how to check the list like you would an array in C or Python. I am not allowed to use fold functions or map or anything like that.
Edit: Updated code, yielding an exception on List.nth:
let rec to_run_length (lst : char list) : (int * char) list =
let n = ref 0 in
match lst with
| [] -> []
| h :: t ->
if h = List.nth t 0 then n := !n + 1 ;
(!n, h) :: to_run_length t ;;
Edit: Added nested match resulting in a function that doesn't work... but no errors!
let rec to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
match to_run_length t with
| [] -> []
| (n, c) :: tail ->
if h <> c then to_run_length t
else (n + 1, c) :: tail ;;
Final Edit: Finally got the code running perfect!
let rec to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
match to_run_length t with
| (n, c) :: tail when h = c -> (n + 1, h) :: tail
| tail -> (1, h) :: tail ;;
One way to answer your question is to point out that a list in OCaml isn't like an array in C or Python. There is no (constant-time) way to index an OCaml list like you can an array.
If you want to code in an imperative style, you can treat an OCaml list like a list in C, i.e., a linked structure that can be traversed in one direction from beginning to end.
To make this work you would indeed have a while statement that continues only as long as the list is non-empty. At each step you examine the head of the list and update your output accordingly. Then replace the list with the tail of the list.
For this you would want to use references for holding the input and output. (As a side comment, where you have int 0 you almost certainly wanted ref 0. I.e., you want to use a reference. There is no predefined OCaml function or operator named int.)
However, the usual reason to study OCaml is to learn functional style. In that case you should be thinking of a recursive function that will compute the value you want.
For that you need a base case and a way to reduce a non-base case to a smaller case that can be solved recursively. A pretty good base case is an empty list. The desired output for this input is (presumably) also an empty list.
Now assume (by recursion hypothesis) you have a function that works, and you are given a non-empty list. You can call your function on the tail of the list, and it (by hypothesis) gives you a run-length encoded version of the tail. What do you need to do to this result to add one more character to the front? That's what you would have to figure out.
Update
Your code is getting closer, as you say.
You need to ask yourself how to add a new character to the beginning of the encoded value. In your code you have this, for example:
. . .
match to_run_length t with
| [] -> []
. . .
This says to return an empty encoding if the tail is empty. But that doesn't make sense. You know for a fact that there's a character in the input (namely, h). You should be returning some kind of result that includes h.
In general if the returned list starts with h, you want to add 1 to the count of the first group. Otherwise you want to add a new group to the front of the returned list.
How could I turn a list of integers, such as [1;2;3], into a single string "123" using fold?
Right now, I think I'm doing:
let int_list_to_string (s : int list) : string =
fold (fun s combine -> combine + .... ) ""
or something along these lines, where .... could be something similar to String.length (which I used in a different fold problem to count characters in a string) but I don't know if this is even remotely correct.
Thank you!
Your basic layout looks right to me. Many things need to be fixed up. Here are a few:
You have to pick a specific fold function to use, List.fold_left or List.fold_right.
The function to be folded takes two parameters. One is the accumulated result and the other is the next input from the list. The order depends on whether you use fold_left or fold_right. Your code sketch has two parameters but one of them is suspiciously named s. This will not be the same s as the input list. The names after fun are new parameter variables introduced at that point.
The OCaml operator for concatenating strings is ^, which is what you should use where you have + (possibly just a placeholder in your code).
You need to convert each int to a string before concatenating. There is a function named string_of_int that does this.
You have to apply the fold to a list. I.e., fold takes 3 arguments but you are supplying only 2 arguments in your code sketch.
Note that the fun needs to concatenate an acc and the next list-element with the ^ - operator. The accumulator of List.fold_left needs to be the same as the output type, so it has to be an empty string: "".
let int_list_to_string lst = List.fold_left (fun acc x -> acc ^ string_of_int x) "" lst
val int_list_to_string : int list -> string = <fun>
# int_list_to_string [1;2;3];;
- : string = "123"
One could also create more advanced strings, e.g. with the list-syntax:
let int_list_to_string_fancy lst =
"[" ^ ( List.fold_left( fun acc x -> acc ^ string_of_int x ^ ";" ) "" lst) ^ "]"
val int_list_to_string_fancy : int list -> string = <fun>
# int_list_to_string_fancy [1;2;3];;
- : string = "[1;2;3;]"
How can I use one of the fold functions to generate a list of integers from 0 to a value n-1? I'm confused about how to get fold_right to return a list rather than returning just an accumulated value.
This is for a helper function that I'm trying to define to solve a larger problem. Here is my attempt:
-I know the base case has to be a list containing only zero, because I do not want to add anything less than zero.
-I know that I need to decrement the value n so that I can put numbers from n-1 to 0 in the list.
let buildList n =
let ibuildList elem list =
list#[n-1]
in List.fold_right ibuildList n [0];;
But I get an error underscoring "n" in the last line saying that the expression has type int but an expression was expected of type 'a list. Isn't n an integer that I'm turning into a list via [n-1]? Where did I go wrong?
Very sorry, I missed at least one step of the reasoning.
A fold is for traversing a collection. Since you want to generate a list and you just have n, not a collection, you can't really use fold in any reasonable way. In fact, what you want to do is more like an unfold. I.e., you want to unfold your n into a list.
It's easy to write this function, but not easy to write it using a fold.
Here's an implementation of unfold in OCaml:
let rec unfold_right f init =
match f init with
| None -> []
| Some (x, next) -> x :: unfold_right f next
Here's how to use unfold_right to generate a list of ints:
let range n =
let irange x = if x > n then None else Some (x, x + 1) in
unfold_right irange 1
Here's how it looks when you run range:
# range 0;;
- : int list = []
# range 8;;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8]
# range 5;;
- : int list = [1; 2; 3; 4; 5]
An alternative version, using the standard Stream module:
(* an infinite stream of natural numbers, starting from 0 *)
let nats =
let rec nats_from n = [< 'n; nats_from (n + 1) >] (* extra syntax *)
in nats_from 0
(* the first n natural numbers: [0; n-1] *)
let range n = Stream.npeek n nats
The piece [< 'n; nats_from (n + 1) >] represents a lazy list with n as its head and the next natural numbers as its tail. Stream.npeek n stream consumes the first n elements of stream and returns them as a list.
Tests with utop:
utop # #load "dynlink.cma";; (* you need these to work with *)
utop # #load "camlp4o.cma";; (* the Stream's syntactic extension *)
utop # range 1;;
- : int list = [0]
utop # range 5;;
- : int list = [0; 1; 2; 3; 4]
utop # range 10;;
- : int list = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]
If you'd like to compile it, use the following commands (you need to use the camplp4o preprocessor):
$ ocamlc -pp camlp4o <filename>.ml
or
$ ocamlopt -pp camlp4o <filename>.ml
The function tally below is really simple: it takes a string s as argument, splits it on non-alphanumeric characters, and tallies the numbers of the resulting "words", case-insensitively.
open Core.Std
let tally s =
let get m k =
match Map.find m k with
| None -> 0
| Some n -> n
in
let upd m k = Map.add m ~key:k ~data:(1 + get m k) in
let re = Str.regexp "[^a-zA-Z0-9]+" in
let ws = List.map (Str.split re s) ~f:String.lowercase in
List.fold_left ws ~init:String.Map.empty ~f:upd
I think this function is harder to read than it should be due to clutter. I wish I could write something closer to this (where I've indulged in some "fantasy syntax"):
(* NOT VALID SYNTAX -- DO NOT COPY !!! *)
open Core.Std
let tally s =
let get m k =
match find m k with
| None -> 0
| Some n -> n ,
upd m k = add m k (1 + get m k) ,
re = regexp "[^a-zA-Z0-9]+" ,
ws = map (split re s) lowercase
in fold_left ws empty upd
The changes I did above fall primarily into three groups:
get rid of the repeated let ... in's, consolidated all the bindings (into a ,-separated sequence; this, AFAIK, is not valid OCaml);
got rid of the ~foo:-type noise in function calls;
got rid of the prefixes Str., List., etc.
Can I achieve similar effects using valid OCaml syntax?
Readability is difficult to achieve, it highly depends on the reader's abilities and familiarity with the code. I'll focus simply on the syntax transformations, but you could perhaps refactor the code in a more compact form, if this is what you are really looking for.
To remove the module qualifiers, simply open them beforehand:
open Str
open Map
open List
You must open them in that order to make sure the List values you are using there are still reachable, and not scope-overridden by the Map ones.
For labelled parameters, you may omit the labels if for each function call you provide all the parameters of the function in the function signature order.
To reduce the number of let...in constructs, you have several options:
Use a set of rec definitions:
let tally s =
let rec get m k =
match find m k with
| None -> 0
| Some n -> n
and upd m k = add m k (1 + get m k)
and re = regexp "[^a-zA-Z0-9]+"
and ws = map lowercase (split re s)
in fold_left ws empty upd
Make multiple definitions at once:
let tally s =
let get, upd, ws =
let re = regexp "[^a-zA-Z0-9]+" in
fun m k ->
match find m k with
| None -> 0
| Some n -> n,
fun g m k -> add m k (1 + g m k),
map lowercase (split re s)
in fold_left ws empty (upd get)
Use a module to group your definitions:
let tally s =
let module M = struct
let get m k =
match find m k with
| None -> 0
| Some n -> n
let upd m k = add m k (1 + get m k)
let re = regexp "[^a-zA-Z0-9]+"
let ws = map lowercase (split re s)
end in fold_left ws empty M.upd
The later is reminiscent of the Sml syntax, and perhaps better suited to proper optimization by the compiler, but it only get rid of the in keywords.
Please note that since I am not familiar with the Core Api, I might have written incorrect code.
If you have a sequence of computations on the same value, then in OCaml there is a |> operator, that takes a value from the left, and applies in to the function on the right. This can help you to "get rid of" let and in. What concerning labeled arguments, then you can get rid of them by falling back to a vanilla standard library, and make your code smaller, but less readable. Anyway, there is a small piece of sugar with labeled arguments, you can always write f ~key ~data instead of f ~key:key ~data:data. And, finally, module names can be removed either by local open syntax (let open List in ...) or by locally shorcutting it to a smaller names (let module L = List in).
Anyway, I would like to show you a code, that contains less clutter, to my opinion:
open Core.Std
open Re2.Std
open Re2.Infix
module Words = String.Map
let tally s =
Re2.split ~/"\\PL" s |>
List.map ~f:(fun s -> String.uppercase s, ()) |>
Words.of_alist_multi |>
Words.map ~f:List.length
I'm having a problem while trying to increment my value of x inside the inner foldl call. I make x equal to shiftValue that's passed in and attempt to increment it whenever I find a #" " or #"*" in the inner foldl call, but the value of x that gets returned is always the same as shiftvalue was when passed in.
The function takes in a tuple of (string, int) where the string will have leading spaces and asterisk chopped off that come before any other characters. Also any spaces or asterisk on the end not followed by any other characters will get chopped off. The int that is passed in is a shiftValue that tracks how many spaces the string was shifted over before getting passed into this function. Whenever I take off a leading space or asterisk I need to increment the shiftValue "x" by one.
The inner foldl call removes asterisks and spaces from the front. The outer foldl call removes them from the back. The asterisks and spaces get removed right, the x value just isn't getting updated.
(*Take string str and get rid of leading and following #"*"s and #" "s. For every
leading #"*" or #" " removed increment the shiftValue returned in the tuple*)
fun trimStarsOnNode (str, shiftValue) =
let
val x = shiftValue
in
((implode(rev (foldl (fn (cur, a) =>
if length a = 0 andalso cur = #"*" then a # []
else
if length a = 0 andalso cur = #" " then a # []
else a # [cur]) [] (rev (foldl (fn (cur, a) =>
if length a = 0 andalso cur = #"*" then (x = x + 1; a # [])
else
if length a = 0 andalso cur = #" " then (x = x + 1; a # [])
else a # [cur]) [] (explode str)))))), x)
end;
trimStarsOnNode ("***hello", 3); (* Should print out ("hello", 6) *) but prints out ("hello", 3)
Look at your x - in the beginning of your function, you do:
val x = shiftValue
Then, later, you try to do this:
x = x + 1
Remember, in SML, you can't change the value of a variable (actually, they're just called values in SML, for that reason). x = x + 1 just compares x and x + 1, so the value of the statement x = x + 1 is boolean false.
As Tayacan says, variables are not mutable in SML. If you want mutability you need to use reference types -- but usually, they are best avoided and it's preferable to stick to functional style.
It's also worth noting that your function is going to be very inefficient (O(n^2)), because of your use of list concatenation and length on every iteration. And it is incorrect, because it will also remove stars in the middle of the string (and then redundantly go over the whole list a second time). Finally, your solution is far too complicated.
FWIW, here is the shortest implementation I can think of, using the Substring library module and the function composition operator o:
fun isStarOrSpace c = (c = #"*" orelse c = #" ")
val trimStars =
let open Substring
in string o dropl isStarOrSpace o dropr isStarOrSpace o full end
This does not use your shiftValue because I don't understand what it's supposed to do. You can easily compute the number of removed characters by comparing the old and new string size. That is, your intended function (IIUC) could easily be expressed on top of mine as
fun trimStarsOnNode(s, shift) =
let val s' = trimStars s in (s', size s - size s' + shift) end
But to be honest, I don't understand what this version would be good for.
Edit: A version that returns the left drop count:
fun trimStars s =
let
open Substring
val ss = dropl isStarOrSpace (dropr isStarOrSpace (full s))
in
(string ss, #2(base ss))
end