I have a question about the way SML of New Jersey interprets lists:
Suppose I have a function f(x : 'a, n : int) : 'a list such that f returns a list of n copies of x, e.g. f(2,5) = [2,2,2,2,2], f(9,0) = [].
So then I go into the REPL, and I check f(9,0) = nil, and it returns true. From this, I assumed that you could use list = nil to check whether a list is the empty list. I used this in a function, and it wouldn't run. I ended up learning that the type definitions are different:
sml:121.2-123.10 Error: operator and operand don't agree [equality type required]
operator domain: ''Z * ''Z
operand: 'a list * 'Y list
in expression:
xs = nil
(Where xs was my list). I then learned that the way to check if a list is the empty list is with null list. Why is this so? What's going on with nil? Can someone explain this behavior to me?
I also note that apparently (case xs = of nil is the same as checking null xs. Does this mean nil is a type?
This is an error related to polymorphism. By default, when an empty list is evaluated, it has the type 'a list. This means that the list can contain elements of any type. If you try to evaluate 1::[], you won't get a type error because of that. This is called polymorphism, it is a feature that allows your functions to take arguments of any type. This can be useful in functions like null, because you don't care about the contents of the list in that case, you only care about its length (in fact, you only care if it's empty or not).
However, you can also have empty lists with different types. You can make your function return an empty int list. In fact, you are doing so in your function.
This is the result in a trivial implementation of your function:
- fun f(x : 'a, n : int) : 'a list =
case n of
0 => []
| _ => x::f(x, n-1);
val f = fn : 'a * int -> 'a list
- f(4,5);
val it = [4,4,4,4,4] : int list
- f(4,0);
val it = [] : int list
As you can see, even if the second argument is 0, your function returns an int list. You should be able to compare it directly with an list of type 'a list.
- it = [];
val it = true : bool
However, if you try to compare two empty lists that have different types and are not type of 'a list, you should get an error. You can see an example of it below:
- [];
val it = [] : 'a list
- val list1 : int list = [];
val list1 = [] : int list
- val list2 : char list = [];
val list2 = [] : char list
- list1 = [];
val it = true : bool
- list2 = [];
val it = true : bool
- list1 = list2;
stdIn:6.1-6.14 Error: operator and operand don't agree [tycon mismatch]
operator domain: int list * int list
operand: int list * char list
in expression:
list1 = list2
Also, case xs of nil is a way of checking if a list is empty, but this is because nil (which is just a way to write []) has the type 'a list by default. (Note that case expressions don't directly return a boolean value.) Therefore, nil is not a type, but 'a list is a polymorphic type that you can compare with lists of any type, but if your empty lists don't have polymorphic type, you will get a type error, which I think what is happening in your case.
Related
In standard ML (Standard ML of New Jersey), we use following syntax to construct tuple
val x = (1, 2);
val u = ();
However we can not construct tuple with only one element
val x = (1); (* normal int *)
val y = (1,); (* python syntax, not valid in SML *)
On the other hand, one element tuple and element itself seems have same type signature.
Can we distinct 'a and a tuple with only one element of type 'a in SML?
If so, how can we construct a one element tuple and what's type signature of it?
Can we distinct 'a and a tuple with only one element of type 'a in SML?
Yes, you can.
Unlike Python, there isn't any special (1,) syntax. But since tuples are equivalent to records with numbered fields, you can create a record with exactly one field named 1 and access it using the #1 macro for getting the first value of a tuple:
- val foo = { 1 = 42 };
val foo = {1=42} : {1:int}
- #1 foo;
val it = 42 : int
You can see that this is actually a 1-tuple by trying to annotate a regular 2-tuple as a record:
- (3.14, "Hello") : { 1 : real, 2 : string };
val it = (3.14,"Hello") : real * string
what's type signature of it?
The type would be { 1 : 'a }. You can preserve the type parameter like this:
type 'a one = { 1 : 'a };
You could get something similar using a datatype:
datatype 'a one = One of 'a
fun fromOne (One x) = x
I think those would use the same amount of memory.
Some functions in the List module fail when the argument is an empty list. List.rev is an example. The problem is the dreaded Value Restriction.
I met the same problem while trying to define a function that returns a list with all but the last element of a list:
let takeAllButLast (xs: 'a list) =
xs |> List.take (xs.Length - 1)
The function works well with nonempty lists, but a version that would handle empty lists fails:
let takeAllButLast (xs: 'a list) =
if List.isEmpty xs then []
else xs |> List.take (xs.Length - 1)
takeAllButLast []
error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : '_a list, etc.
I tried several things: making it an inline function, not specifying a type for the argument, specifying a type for the returned value, making the function depend on a type argument, and using the Option type to obtain an intermediate result later converted to list<'a>. Nothing worked.
For example, this function has the same problem:
let takeAllButLast<'a> (xs: 'a list) =
let empty : 'a list = []
if List.isEmpty xs then empty
else xs |> List.take (xs.Length - 1)
A similar question was asked before in SO: F# value restriction in empty list but the only answer also fails when the argument is an empty list.
Is there a way to write a function that handles both empty and nonempty lists?
Note: The question is not specific to a function that returns all but the last element of a list.
The function itself is completely fine. The function does not "fail".
You do not need to modify the body of the function. It is correct.
The problem is only with the way you're trying to call the function: takeAllButLast []. Here, the compiler doesn't know what type the result should have. Should it be string list? Or should it be int list? Maybe bool list? No way for the compiler to know. So it complains.
In order to compile such call, you need to help the compiler out: just tell it what type you expect to get. This can be done either from context:
// The compiler gleans the result type from the type of receiving variable `l`
let l: int list = takeAllButLast []
// Here, the compiler gleans the type from what function `f` expects:
let f (l: int list) = printfn "The list: %A" l
f (takeAllButLast [])
Or you can declare the type of the call expression directly:
(takeAllButLast [] : int list)
Or you can declare the type of the function, and then call it:
(takeAllButLast : int list -> int list) []
You can also do this in two steps:
let takeAllButLast_Int : int list -> int list = takeAllButLast
takeAllButLast_Int []
In every case the principle is the same: the compiler needs to know from somewhere what type you expect here.
Alternatively, you can give it a name and make that name generic:
let x<'a> = takeAllButLast [] : 'a list
Such value can be accessed as if it was a regular value, but behind the scenes it is compiled as a parameterless generic function, which means that every access to it will result in execution of its body. This is how List.empty and similar "generic values" are implemented in the standard library.
But of course, if you try to evaluate such value in F# interactive, you'll face the very same gotcha again - the type must be known - and you'll have to work around it anyway:
> x // value restriction
> (x : int list) // works
I tried the following:
fun consAll (nil, n) = [n]
| consAll ((x::xs), n) = [[n::x], [consAll(xs, n)]];
But it returns this error:
"Error: operator and operand don't agree [circularity]
operator domain: 'Z list list * 'Z list list list
operand: 'Z list list * 'Z list list
in expression:
((n :: x) :: nil) :: (consAll (,) :: nil) :: nil"
Please tell me where I am going wrong, I am a beginner to SML.
The SML list construction syntax isn't completely straightforward. Since we use [...] to construct literal lists, it is tempting to think we could also use that notation to destructure lists and cons elements onto the head of lists (as we can, for instance, in Prolog). But the cons operator, ::, is just an infix value constructor which takes an item of type 'a and a list of type 'a list and returns a new list with the item consed onto the head of the list. If you then enclose the result of evaluating this construction in square brackets, you have now wrapped the resulting list in another list:
- val xs = [2,3,4];
val xs = [2,3,4] : int list
- [1::xs];
val it = [[1,2,3,4]] : int list list
There are two additional errors in your definition:
First, you are creating a two-item list when you mean to be consing a head onto the tail of a list in the body of your second guarded function definition.
Second, your base is incorrect:
fun consAll (nil, n) = [n]
This says, if the list of lists is empty, then return a singleton list containing the item to be consed onto every list. But you are defining a function which should cons n onto the head of every list which is a member of the list in the first argument. When you run out of lists in the first argument, you should just return an empty list, because there are not more lists to be consed on to. Make sense?
Here are two ways of writing the function you describe. One using simple recursion, the other using the higher-order function List.map:
fun consAll ([], _) = []
| consAll ((x::xs), n) = (n::x) :: consAll(xs, n)
fun mapCons x lists = List.map (fn ls => x :: ls) lists
[[n::x], [consAll(xs, n)]] creates a two-element list but you want to prepend to a list. Use (n :: x) :: consAll(xs, n) instead.
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!
using ML as a programming language we have list and tuple, in the case of lists we can form a list from another list by removing or appending elements from and to the original list, for example if we have:
val x = [7,8,9] : int list
in REPL we can do some operations like the following:
- hd x;
val it = 7 : int
- tl x;
val it = [8,9] : int list
now if we have a tuple lets say:
val y = (7,8,9) :int*int*int
now the question is that , can we have a smaller tuple by removing the first element from the original tuple ? in other words , how to remove (#1 y) and have new tuple (8,9) in a similar way that we do it in the case of list.
Thanks.
Tuples are very different from lists. With lists, size need not be known at compile time, but with tuples, not only should the number of elements be known at compile time, the type of each element is independent of the others.
Take the type signature of tl:
- tl;
val it = fn : 'a list -> 'a list
It is 'a list -> 'a list - in other words tl takes a list of 'a and returns another one. Why don't we have one for tuples as well? Assume we wanted something like
y = (1,2,3);
tail y; (* returns (2,3) *)
Why does this not make sense? Think of the type signature of tail. What would it be?
In this case, it would clearly be
'a * 'b * 'c -> 'b * 'c
Takes product of an 'a, a 'b and a 'c and returns a product of
a 'b and a 'c. In ML, all functions defined must have a statically determined
type signature. It would be impossible to have a tail function for tuples that
handles all possible tuple sizes, because each tuple size is essentially a different type.
'a list
Can be the type of many kinds of lists: [1,2,3,4], or ["A", "short", "sentence"], or
[true, false, false, true, false]. In all these cases, the value of the type
variable 'a is bound to a different type. (int, string, and bool). And 'a list can be a list of any size.
But take tuples:
(1, true, "yes"); (* (int * bool * string) *)
("two", 2) (* (string, int) *)
("ok", "two", 2) (* (string, string, int) *)
Unlike list, these are all of different types. So while the type signature of all lists is simple ('a list), there is no 'common type' for all tuples - a 2-tuple has a different type from a 3-tuple.
So you'll have to do this instead:
y = (7, 8, 9);
(a, b, c) = y;
and a is your head and you can re-create the tail with (b,c).
Or create your own tail:
fun tail (a,b,c) = (b, c)
This also gives us an intuitive understanding as to why such a function would not make sense: If is impossible to define a single tail for use across all tuple types:
fun tail (a,b) = (b)
| tail (a,b,c) = (b, c) (* won't compile *)
You can also use the # shorthand to get at certain elements of the tuple:
#1 y; (* returns 7 *)
But note that #1 is not a function but a compile time shorthand.
Lists and tuples are immutable so there is no such thing like removing elements from them.
You can construct a new tuple by decomposing the original tuple. In SML, the preferred way is to use pattern matching:
fun getLastTwo (x, y, z) = (y, z)
If you like #n functions, you can use them as well:
val xyz = (7, 8, 9)
val yz = (#2 xyz, #3 xyz) (* (8, 9) *)