What does (string * string) list -> (string -> string) mean? - ocaml

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

Related

Ocaml: Function to uppercase the first element of a list

I have the following function (from the Real World Ocaml book) that works perfectly (with the Core library):
let upcase_first_entry line =
match String.split ~on:',' line with
| [] -> assert false
| first :: rest -> String.concat ~sep: "," (String.uppercase first :: rest);;
So when i evaluate:
upcase_first_entry ("one,two");;
I get:
- : string = "ONE,two"
From my understanding of the function, the string is first transform into a list of string and then the uppercase function is applied and finally the output is transformed back to a string.
So I tried the following function:
List.map ~f:(fun (first :: last) -> (String.uppercase first :: last)) ["one","two"];;
where I pass to the function the list directly. But I get the following error:
Error: This pattern matches values of type 'a list
but a pattern was expected which matches values of type
string * string
Can someone guide me as to why this is throwing an error ?
Typing the argument ["one", "two"] directly into the interpreter gives
- : (string * string) list = [("one", "two")]
That is, a list of pairs of strings not a list of strings. You probably meant to type ["one"; "two"] which is a string list. In OCaml, the , is used for making pairs and other tuples, even if the parentheses are not given.
The next problem is that List.map applies a function to each element of the list and creates a new list. In this situation, it expects an f that maps a string to something. But your anonymous function maps a list of strings to a list of strings (string list -> string list).
In this case, the simplest solution is probably not to use List.map and to simply apply your function to the argument.
(fun (first :: last) -> (String.uppercase first :: last)) ["one";"two"]
The resulting warning indicates that a case is missing. Indeed, the anonymous function is not defined for the empty list. This does not matter for the given argument, but, in general, it would be better to define what should happen, and it gets rid of the warning:
(function (first :: last) -> (String.uppercase first :: last) | [] -> []) ["one";"two"]

Type Mismatch in ML List.filter

I am trying to write a simple filter function in ML. The idea is that the function only_capitals takes a list of strings and returns a list of strings, with only the strings that start with a capital letter. Here is my implementation, but I am getting a type-error that I do not understand:
fun only_capitals (strs : string list) =
let
fun isCapitalized (str) = Char.isUpper(String.sub(str, 0))
in
List.filter(isCapital, strs)
end
Here is the error:
hw3provided.sml:5.18-5.27 Error: unbound variable or constructor: isCapital
hw3provided.sml:5.6-5.34 Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z -> bool
operand: _ * string list
in expression:
List.filter (<errorvar>,strs)
val it = () : unit
The first error is caused by a typo; "isCapital" is not the name of the function you defined.
The second error looks extra strange because of the first error – the type _ refers to the type of isCapital.
If you fix the first error, the second should look more like
Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z -> bool
operand: (string -> bool) * string list
in expression:
List.filter (isCapitalized,strs)
What the compiler is trying to say is that you're passing the pair (isCapitalized,strs) to filter where it expects a function of type 'Z -> bool.
If you look at the type of List.filter, you'll notice that it is ('a -> bool) -> 'a list -> 'a list – it's a curried function.
What you should write is
fun only_capitals (strs : string list) =
let
fun isCapitalized (str) = Char.isUpper(String.sub(str, 0))
in
List.filter isCapitalized strs
end

operator and operand don't agree [tycon mismatch] - sml assuming the wrong list type

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!

SML function type

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).

Declare a function SML

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)