I have a function foo that takes in a character. I want to map that function over each character in a string.
fun foo (ch : char) =
ch;
fun bar (str : string) =
map foo [(str)];
Clearly this won't work due to a string being applied to a function that expects a char. So I tried using String.explode(str) to break it up into a char array, but then I can't seem to map over each char in the array and apply the char to the foo function.
fun foo (ch : char) =
ch;
fun bar (str : string) =
map foo [(String.explode(str))];
How can I map a function over each character in a string?
EDIT:
I wanted to change foo to take 2 parameters
fun foo(ch : char, i : int) =
ch;
fun bar(str : string) =
map foo (String.explode(str), 1);
But that gives me a tycon mismatch
operator domain: (char * int) list
operand: char list * int
How come previously the String.explode(str) was understood by the map function to map over each char, but now it sees it as a full char list?
EDIT 2: Nevermind, figured it out.
fun bar(str : string) =
map (fn x => foo (x, 1)) (String.explode(str));
When you want to map over each character, then the list you give to map must be a list of characters. explode returns a list of characters, so using explode is definitely the right idea. But you're putting the list returned by explode into another list, resulting in a list of lists of characters. That's why you get a type error.
Just remove the outer list and your code will work as you intend.
- String.map Char.succ "HAL";
> val it = "IBM" : string
Related
This might be a super dumb question, but I don't get it.
What does
(string * string) list -> (string -> string) mean?
Especially the last part (string -> string). How can you achieve that?
I thought it'd be an inner function but it isn't I guess.
string -> string indicates a function which takes a string and returns a string. Similarly, int -> int would indicate a function which takes an int and turns an int.
string * string indicates a tuple of two strings. (string * string) list indicates a list of those tuples.
So:
(string * string) list -> (string -> string)
Indicates a function which takes a list of tuples of two strings, and returns a function which takes a string and returns a string.
It's a good idea to get familiar with this syntax as you'll be seeing a lot of it.
A very simple function that matches this type is shown below. Please note that the pattern-matching contained within is non-exhaustive.
let f : (string * string) list -> (string -> string) =
fun ((a,b)::_) -> fun x -> x ^ a ^ b
When trying this at the top-level, you will see the below type. Due to the way functions work in OCaml, it is equivalent to the type signature you asked about, despite the missing parentheses.
(string * string) list -> string -> string
I am currently teaching myself ocaml for a programming language class and I am trying to figure out how to specify a function parameter and return type as a List.
I have create a program that reads a file char by char stores each char in a List, reverses the list then returns the List.
Current code:
(*
Creating a function that will read all the chars
in a file passed in from the command argument.
This function takes a parameter of type List.
This function will return a List.
*)
let read_file (char_List : List) : List =
let char_in = open_in Sys.argv.(1) in (* Creating a file point/in_channel *)
try
while true do
let c = input_char char_in in (* Getting char from the file *)
char_List := c :: !char_List (* Storing the char in the list *)
done
with End_of_file ->
char_List := List.rev !char_List; (* End of file was reaching reversing char list *)
close_in char_in; (* Closing the file pointer/in_channel *)
;;
(* Storing the result of read_file to buffer which buffer is of type list *)
let buffer = ref [] in
read_file(buffer);
print_string "\nThe length of the buffer is: ";
print_int (List.length !buffer); (* Printing length of the list *)
print_string ("\n\n");
List.iter print_char !buffer; (* Iterating through the list and print each element *)
If I remove specifying the parameter type and return type of List the code runs as intended. However; I would like to specify the type of the parameter and return type as a List.
How do you specify the function parameter and return type to be a List?
First, List is a module not a type, so you probably meant list. However, you cannot annotate with only list, because a list is not a type by itself: you do not want to have a list of unknowable things, but a list of elements which have themselves a known type. For instance, in your case, you have a list of characters, which can be written as char list. Similarly, a list of integers will be typed int list.
More precisely, list is not a type by itself but a type constructor which takes as argument a type for the elements of the list and returns a type for the list of such elements.
p.s. : if you are learning OCaml you could try to rewrite your code without using references to get used to a more functional style.
As #octachron correctly pointed out, List is not a correct type in ocaml. You probably meant 'a list. Looking at your code, you can correct your code by addressing the 2 points below:
Correct function signature as follows,
let read_file (char_List: 'char list ref) : 'char list =
Add !char_List after done and !char_List.
You corrected code may look like the following,
let read_file (char_List: 'char list ref) : 'char list =
let char_in = open_in Sys.argv.(1) in (* Creating a file point/in_channel *)
try
while true do
let c = input_char char_in in (* Getting char from the file *)
char_List := c :: !char_List (* Storing the char in the list *)
done;
!char_List
with End_of_file ->
char_List := List.rev !char_List; (* End of file was reaching reversing char list *)
close_in char_in; (* Closing the file pointer/in_channel *)
!char_List
While this works, however, you may want to prefer a more functional approach in ocaml. A version without mutation and with recursive function could be implemented as follows:
let get_chars file =
let rec loop ic acc =
match Pervasives.input_char ic with
| c -> loop ic (c::acc)
| exception(End_of_file) -> List.rev acc
in
let ic = Pervasives.open_in file in
loop ic []
Then in ocaml toploop(repl) you can execute the function as such
get_chars "/tmp/union_find.ml";;
or perhaps
get_chars Sys.argv.(1);;
I have a pretty simple code that's supposed to transform a list of tuples (int * string), into two lists, one list of ints and one list of strings - basically a list of tuples into a tuple of lists.
fun unzip_single_int[] : int list = []
| unzip_single_int(x::xs) : int list =
x :: unzip_single_int(xs)
fun unzip_single_string[] : string list = []
| unzip_single_string(x::xs) : string list =
x :: unzip_single_string(xs)
fun unzip[] : (int list * string list) = ([], [])
| unzip([twopls]) : (int list * string list) =
let
val x : int list = unzip_single_int(twopls);
val y : string list = unzip_single_string(twopls); (* this is line 28 btw *)
in
(x, y)
end
And the error:
zip.sml:28.7-28.52 Error: operator and operand don't agree [tycon mismatch]
operator domain: string list
operand: int list
in expression:
unzip_single_int twopls
For some reason the compiler believes val y : string list = unzip_single_string(twopls) is referring to an int list.
Interestingly enough, when I switch the two around, when I change:
val x : int list = unzip_single_int(twopls);
val y : string list = unzip_single_string(twopls);
to
val y : string list = unzip_single_string(twopls);
val x : int list = unzip_single_int(twopls);
The error switches too:
zip.sml:28.7-28.47 Error: operator and operand don't agree [tycon mismatch]
operator domain: int list
operand: string list
in expression:
unzip_single_int twopls
For some reason, whatever the second call is, it's going to assume that its whatever the last call's type was. Why is it doing this? How do I overcome this? I made it very clear in the two other functions definitions that they are int lists and string lists respectively, so why does SML think that I'm sending it a string list when I clearly defined it as an int list ?
Thanks!
The answer to your question is type inference. You haven't given any type for twopls or an argument type for unzip, and you are calling unzip_single_int(twopls) when you make a value declaration for x. Therefore, SML infers that twopls is an int list, because the type of your function unzip_single_int is int list -> int list, which means it takes an int list as input and returns an int list.
After SML infers that twopls is an int list, you are trying to call unzip_single_string(twopls). However, the type of the function unzip_single_string is string list -> string list, therefore it expects an expression of string list as an input. But now twopls is an int list, so you get a type error.
However, your function definitions don't change anything about the list, they return the exact same list, I'm guessing you want them to return either the first or the second element in the tuple, so you should add that. Your unzip function is supposed to have the type (int * string) list -> int list * string list. Therefore, try to pattern match on the int * string elements you have in your list. Normally you would pattern match a list like x :: xs, but if you know the elements are tuples and if you want to access them, you can pattern match them like (num, str) :: xs, where num is an int variable and str is a string variable. You should be able to figure out the rest. Good luck!
I have a hard time understanding the Type of a certain SML function i need to create.
It is a helper function that should return the longest string from a list of strings.
The type should be: (int * int -> bool) -> string list -> string
How should i read this and how can i create a function that would match?
I started by following simple code:
fun helper(x,y)=x>y
But now i should have this method to return a string list and then a string. But i seem to be missing some points here.
This is the signature of a curried function: (int * int -> bool) -> string list -> string
(int * int -> bool): this is the first argument, and it is a function that receives a tuple of two integers and returns a boolean. Looks like a predicate function.
string list: this is the second argument, a list of strings
string: and this is the resulting type of your function.
For instance, in the course of Programming Languages (which appears to be the source of the question) the function in question should look somewhat like:
fun longest_string_helper f xs = ...
Where
f is a function value of type (int * int -> bool)
xs is a list value of type string list
And of course the function returns a string value.
Notice that the arguments in the function declaration are separated by spaces, and not within a tuple pattern. That evidences that this is a curried function. You can read about this in the course reading notes for section 3, under Another Closure Idiom: Currying and Partial Application (page 11).
How to declare a function suffixsen : string list -> string list ?
After declaring types inside the parens, declare the function's return type on the outside with :return-type. At least in SMLnj. I found this through trial and error, can't find documentation for it.
fun suffixson (xs: string list ): string list =
map (fn x => x ^ "son") xs
The syntax to define a function with one argument in sml is:
fun functionName argumentName = functionBody
or
fun functionName (argumentName : argumentType) = functionBody
if you want to specify the type explicitly. So to define a function named suffixsen of type string list -> string list, you can do:
fun suffixsen (strings : string list) = someExpressionThatReturnsAStringList
Edit in response to you comment:
In order to append "son" to each string in the list, you should look at the ^ operator[1], which concatenates string, and the map function which performs an operation for each element in a list.
[1] http://www.standardml.org/Basis/string.html#SIG:STRING.^:VAL (copy and paste this link in your browser - for some reason I can't get this to be clickable)