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;]"
Related
So im really confused as i am new to sml and I am having trouble with syntax of how i want to create my function.
the instructions are as follows...
numberPrefix: char list → string * char list
Write a function named numberPrefix that returns (as a pair) a string representing the digit characters at the
beginning of the input list and the remaining characters after this prefix. You may use the Char.isDigit and
String.implode functions in your implementation.
For example,
numberPrefix [#"a", #"2", #"c", #" ", #"a"];
val it = ("", [#"a", #"2", #"c", #" ", #"a") : string * char list
numberPrefix [#"2", #"3", #" ", #"a"];
val it = ("23", [#" ", #"a"]) : string * char list
Here is my code so far...
fun numberPrefix(c:char list):string*char list =
case c of
[] => []
|(first::rest) => if isDigit first
then first::numberPrefix(rest)
else
;
I guess what i am trying to do is append first to a seperate list if it is indeed a digit, once i reach a member of the char list then i would like to return that list using String.implode, but I am banging my head on the idea of passing in a helper function or even just using the "let" expression. How can I essentially create a seperate list while also keeping track of where i am in the original list so that I can return the result in the proper format ?
First of all, the function should produce a pair, not a list.
The base case should be ("", []), not [], and you can't pass the recursive result around "untouched".
(You can pretty much tell this from the types alone. Pay attention to types; they want to help you.)
If you bind the result of recursing in a let, you can access its parts separately and rearrange them.
A directly recursive take might look like this:
fun numberPrefix [] = ("", [])
| numberPrefix (cs as (x::xs)) =
if Char.isDigit x
then let val (number, rest) = numberPrefix xs
in
((str x) ^ number, rest)
end
else ("", cs);
However, splitting a list in two based on a predicate – let's call it "splitOn", with the type ('a -> bool) -> 'a list -> 'a list * 'a list – is a reasonably useful operation, and if you had that function you would only need something like this:
fun numberPrefix xs = let val (nums, notnums) = splitOn Char.isDigit xs
in
(String.implode nums, notnums)
end;
(Splitting left as an exercise. I suspect that you have already implemented this splitting function, or its close relatives "takeWhile" and "dropWhile".)
Hello guys I am trying to make a simple recursive method that simply takes in an accumulator and a target value. Then add one to the accumulator until it reaches the target value. I am very new to Ocaml but have a decent background in java.
I wrote up a quick snippet of code that shows what I want to do in java:
public static int rec(int acc,int target) {
if (acc == target) {
return 0;
} else {
return rec(acc+1, target);
}
}
here is my attempt to mimic this code in Ocaml:
let h_sequence x =
let rec helper acc x = function
| acc -> x
| _ -> helper acc+1 x
in
helper 0 x;;
however I get the following error:
Error: This expression has type 'a -> 'b -> 'a
but an expression was expected of type int
Here is how I am trying to understand the Ocaml code. So we have a function h_sequence that has a paramater x. Inside of the function h_sequence we have a recursive function named helper which has two paramaters acc and x. If acc = x then return x. Else start the recursion by passing in helper, add one to the acc and then return x. And after the in it is passing the helper function, setting 0 for the acc and setting x as x. Please let me know if my logic is off. Any help will be much appreciated!
edit new code:
let h_sequence x =
let rec helper acc x =
if acc = x then
acc
else
helper (acc+1) x
in
helper 0 x;;
As #Flux says, your helper function has 3 parameters. You should also be aware that the pattern acc will match all values. Patterns consist essentially of constants, and any names appearing in a pattern will match (and be bound to) any corresponding value.
To compare x against acc you should just use an if statement.
Since you don't really want to use pattern matching, you can simplify things by removing function. You'll end up with something like this for the helper function:
let rec helper acc x =
if x = acc then (* One of the cases *)
else (* The other case *)
... we have a recursive function named helper which has two parameters acc and x.
You are getting the error because the recursive function helper actually has three "parameters": acc, x, and another "parameter" that that is matched using function. The error message has given you this clue ('a -> 'b -> 'a).
Let's now look at the helper function:
let rec helper acc x = function
| zzz -> x (* Equivalent to `| _ -> x` *)
| _ -> helper acc+1 x
Mistakes:
function does pattern matching. Everything will match the pattern zzz, which means that the next pattern (| _ -> helper acc+1 x) is useless because it will never be matched. Note that I've changed the pattern's name from your acc to zzz in order to emphasize that function actually matching patterns.
helper acc+1 x is equivalent to (helper acc) + 1 x, which is not what you want. It should be helper (acc+1) x instead.
Solution
let rec helper acc x =
if acc >= x then 0
else helper (acc+1) x
You should use >= instead of = to handle the case where x is negative.
I have made function that takes a list and a list of lists and returns a new list of lists.
let rec calculator list SS =
match (List.item(0) SS) with
|[] -> []
|_ -> match (validate list (List.item(0) SS)) with
|(validate theCode list) -> List.append [(List.item(0) SS)] (calculator list (SS.[1..]))
|_ -> (calculator list (SS.[1..]))
validate is a function that returns two tupled ints. example (1,1)
list is a list of four ints
SS is a list of lists with four ints
theCode is a list of four ints
i get the error "The pattern discriminator 'validate' is not defined."
Perhaps this is a silly question but none the less i don't know the answer to it.
Is it not allowed to use a function as an argument in a match expression. Or is it something entirely different going on here?
to the best of my knowledge the two validate functions will return two tupled ints and therefore should be able to match upon that.
If your question is how to get this to compile then you only need a small change – a function call is not itself a pattern, so you need to bind to a value and use a when guard:
let rec calculator list SS =
match (List.item(0) SS) with
| [] -> []
| _ ->
match (validate list (List.item(0) SS)) with
// vvvvvvvvvv
| x when x = (validate theCode list) ->
List.append [(List.item(0) SS)] (calculator list (SS.[1..]))
| _ -> (calculator list (SS.[1..]))
However, if your question is indeed "what is the preferred method", then while that's too subjective for this site (IMO), I'll submit this as an option that I consider ideally readable for this logic:
let rec calculator list (h::t) =
if List.isEmpty h then h
elif validate list h = validate theCode list then h::(calculator list t)
else calculator list t
(This assumes that SS is an F# list and not a System.Collections.Generic.List.)
This is not actually an answer to the question of how to implement the when guard, since #ildjarn answered that for you.
I think you'd actually be better served by a library function. What you're trying to do appears to be to filter out elements which don't pass validation, but also to stop on the first empty element. If you can guarantee that you definitely want to loop through every element of SS, you could simply do
let calculator list = List.filter (fun s -> validate list s = validate theCode list)
If it's you must stop at the empty element, you could define a function that cuts the list at the first empty element, something like
let upToElement element list =
let rec loop acc = function
| [] -> List.rev acc
| h :: t when h = element -> List.rev acc
| h :: t -> loop (h :: acc) t
loop [] list
then you can do
let calculator list =
upToElement [] >> List.filter (fun s -> validate list s = validate theCode list)
I tried to pass a string in to get a reversed string. Why can't I do this:
let rec reverse x =
match x with
| "" -> ""
| e ^ s -> (reverse s) ^ e;;
The compiler says it's a syntax error. Can't I use ^ to destructure parameters?
The reason for this is that strings are not represented as a datatype in the same way as lists are. Therefore, while cons (::) is a constructor, ^ is not. Instead, strings are represented as a lower level type without a recursive definition (as lists are). There is a way to match strings as a list of characters, using a function from SML (which you can write in OCaml) called explode and implode which -- respectively -- take a string to a char list and vice versa. Here's an example implementation of them.
As Kristopher Micinski explained, you can't decompose strings using pattern matching as you do with lists.
But you can convert them to lists, using explode. Here's your reverse function with pattern matching using explode and its counterpart implode:
let rec reverse str =
match explode str with
[] -> ""
| h::t -> reverse (implode t) ^ string_of_char h
Use it like this:
let () =
let text = "Stack Overflow ♥ OCaml" in
Printf.printf "Regular: %s\n" text;
Printf.printf "Reversed: %s\n" (reverse text)
Which shows that it works for single-byte characters but not for multi-byte ones.
And here are explode and implode along with a helper method:
let string_of_char c = String.make 1 c
(* Converts a string to a list of chars *)
let explode str =
let rec explode_inner cur_index chars =
if cur_index < String.length str then
let new_char = str.[cur_index] in
explode_inner (cur_index + 1) (chars # [new_char])
else chars in
explode_inner 0 []
(* Converts a list of chars to a string *)
let rec implode chars =
match chars with
[] -> ""
| h::t -> string_of_char h ^ (implode t)
When you write a pattern matching expression, you cannot use arbitrary functions in your patterns. You can only use constructors, which look like unevaluated functions. For example, the function "+" is defined on integers. So the expression 1+2 is evaluated and gives 3; the function "+" is evaluated, so you cannot match on x+y. Here is an attempt to define a function on natural numbers that checks whether the number is zero:
let f x = match x with
| 0 -> false
| a+1 -> true
;;
This cannot work! For the same reason, your example with strings cannot work. The function "^" is evaluated on strings, it is not a constructor.
The matching on x+1 would work only if numbers were unevaluated symbolic expressions made out of the unevaluated operator + and a symbolic constant 1. This is not the case in OCAML. Integers are implemented directly through machine numbers.
When you match a variant type, you match on constructors, which are unevaluated expressions. For example:
# let f x = match x with
| Some x -> x+1
| None -> 0
;;
val f : int option -> int = <fun>
This works because the 'a option type is made out of a symbolic expression, such as Some x. Here, Some is not a function that is evaluated and gives some other value, but rather a "constructor", which you can think of as a function that is never evaluated. The expression Some 3 is not evaluated any further; it remains as it is. It is only on such functions that you can pattern-match.
Lists are also symbolic, unevaluated expressions built out of constructors; the constructor is ::. The result of x :: y :: [] is an unevaluated expression, which is represented by the list [x;y] only for cosmetic convenience. For this reason, you can pattern-match on lists.
type a = [(Int,Int,Int,Int)]
fun:: a -> Int
func [a,b,c,d] = ?
I have a list of tuples like this what i required is to apply list comprehensions or pattern matching .. example taking sum or filter only divide 2 numbers ... i just want a start how to access values and or a list comprehension to this List of Tuples
To sum up the as, use something like this:
type A = [(Int, Int, Int, Int)]
func :: A -> Int
func tuples = sum [a | (a, b, c, d) <- tuples]
Also note that a type alias must begin with an upper case letter. Lower case letters are used for type variables.
hammar's answer covered list comprehensions, the basic schema for recursive functions using pattern matching is:
f [] = ..
f ((a,b,c,d):xs) = ..
So you need to specify a base case for a list containing no 4-tuples, and a recursive case for when the list consists of a 4-tuple (a,b,c,d) followed by a (possibly empty, possibly non-empty) list of 4-tuples xs. The pattern on the second line is a nested pattern: it first matches the list against a pattern like (x:xs), i.e. element x followed by rest of list xs; and then it matches x against the 4-tuple structure.
Below, I'll give some basic examples. Note that you can also write this with standard higher-order functions, such as filter and map, and I'm deliberaty not mentioning things like #-patterns and strictness. I do not recommend doing it like this, but it's just to give you an idea!
When you want to sum the first part of the tuples, you could do it like this:
sum4 :: [(Int,Int,Int,Int)] -> Int
sum4 [] = 0
sum4 ((a,b,c,d):xs) = a + sum4 xs
If you want to filter out the tuples where all of a,b,c and d are even:
filter4allEven :: [(Int,Int,Int,Int)] -> [(Int,Int,Int,Int)]
filter4allEven [] = []
filter4allEven ((a,b,c,d):xs)
| all even [a,b,c,d] = (a,b,c,d) : filter4AllEven xs
| otherwise = filter4AllEven xs
(If the use of all confuses you, just read even a && even b && even c && even d)
And finally, here's a function that returns all the even tuple components (tuples themselves can't be even!) in the same order as they appear in the argument list:
evenTupleComponents :: [(Int,Int,Int,Int)] -> [Int]
evenTupleComponents [] = []
evenTupleComponents ((a,b,c,d):xs) = [x | x <- [a,b,c,d], even x] ++ evenTupleComponents
Once you do a couple of exercises like these, you'll see why using standard functions is a good idea, since they all follow similar patterns, like applying a function to each tuple separately, including or excluding a tuple when it has some property or, more generally, giving a base value for the empty list and a combining function for the recursive case. For instance, I would write evenTupleComponents as evenTupleComponents = filter even . concatMap (\(a,b,c,d) -> [a,b,c,d]), but that's a different story :)