Hi i am getting compilation errors in the following SML code, can someone help?
Error: operator and operand don't agree [UBOUND match]
operator domain: 'Z list
operand: ''list
in expression:
null mylist
stdIn:4.15-4.24 Error: operator and operand don't agree [UBOUND match]
operator domain: 'Z list
operand: ''list
in expression:
hd mylist
stdIn:6.19-6.36 Error: operator and operand don't agree [UBOUND match]
operator domain: 'Z list
operand: ''list
in expression:
tl mylist
stdIn:6.10-7.21 Error: operator is not a function [circularity]
operator: 'Z
in expression:
(exists_in (item,tl mylist)) exists_in
code:
fun exists_in (item: ''int, mylist:''list) =
if null mylist
then false
else if (hd mylist) = item
then true
else exists_in(item, tl mylist)
exists_in(1,[1,2,3]);
What each of the error messages is telling you is that you're applying a function to something of the wrong type. For example, null is of type 'a list -> bool, and so expects to be applied to an argument of type 'a list. In exists_in, you're applying null to something of type ''list on line 4.
SML also provides type inference, so there's no real need to specify the types of your arguments (though it can be useful for debugging). If you do want to specify the types, as molbdnilo commented, the types you are looking for are int and int list, or ''a and ''a list ('' a being a type variable for equality types).
Unrelatedly, perhaps a more idiomatic way to write your function is do define it by case analysis on the structure of your list, rather than using boolean checks. The advantage of this is that you are immediately given the data supporting the boolean check on whether or not the list is empty, rather than checking and then extracting the data. For example:
fun exists_in (item, []) = false
| exists_in (item, h::t) = (item = h) orelse exists_in (item, t)
Related
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
I am trying to reverse a list in SML with the following implementation
fun reverse x y =
case x of
[] => y
| x::xs => reverse(xs, x::y)
;
The error messages I get is impenetrable:
trial.sml:1.6-4.35 Error: case object and rules don't agree [tycon mismatch]
rule domain: 'Z list * 'Z list
object: ('Z list * 'Z list) * 'Y
in expression:
(case (arg,arg)
of (x,y) =>
(case x
of nil => y
| :: <pat> => reverse <exp>))
trial.sml:1.6-4.35 Error: right-hand-side of clause doesn't agree with function result type [tycon mismatch]
expression: 'Z -> _
result type: 'Y list
in declaration:
reverse = (fn arg => (fn <pat> => <exp>))
However if I change the signature to be fun reverse(x: 'a list, y: 'a list)
then it works why is this so? Is there a way to write this so that I dont need to have to write the type 'a list ?
x y differs from (x,y).
In the first line of the definition
fun reverse x y =
You seem to be trying to write a curried function of type
fn: a' list -> a' list -> 'a list
but in the recursive call
reverse(xs, x::y)
you are treating reverse as if it were and uncurried function of type
fn: a' list * a' list -> 'a list
The problem has nothing at all to do with whether or not you add a type annotation but instead it has to do with where you put parenthesis (and commas, if any). There are two valid fixes depending on what you want the type to be. Since this seems to be homework (there is no obvious non-homework reason to avoid the built-in rev), I'll leave the details to you.
I'm trying to implement flatten : 'a list list -> 'a list list in SML.
I thought this should be relatively straight forward with higher order functions. My implementation is
val flatten = List.reduce (op #) []
However I'm getting a bizarre error message: "append.sml:1.6-1.36 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)". Thus when I try to flatten an int list list I get a type error:
:> flatten [[1,2],[3]];
stdIn:2.1-2.20 Error: operator and operand don't agree [literal]
operator domain: ?.X1 list list
operand: int list list
in expression:
flatten ((1 :: 2 :: nil) :: (3 :: nil) :: nil)
As the error message hints, you ran into the value restriction -- see here for an explanation. The solution is very simple: just "eta-expand" your definition, i.e., make the parameter explicit instead of relying on partial application:
fun flatten xs = List.reduce op# [] xs
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.
I have a question about mapping lists in ML the problem seems to repeat itself, I have the current datatypes defined :
datatype 'a seq = Nil | Cons of 'a * (unit -> 'a seq);
datatype 'a generic_list = List of 'a list
|Seq of 'a seq;
i'm now trying to write the following function that's supposed to recieve a "'a generic_list" and return a "int generic_list:
val rec generic_map = fn (f,List(lst)) => if lst=nil then List([])
else List(f(List.hd(lst))::generic_map(f,List( List.drop(lst,1))));
That code doesn't compile with the error of : right-hand-side of clause doesn't agree with function result type [tycon mismatch] expression:
'Z generic_list
result type: 'Z list
in declaration:
generic_map =
(fn (f,List lst) =>
if lst = nil
then List nil
else List
(f (List.hd lst) ::
generic_map (f,List (List.drop (lst,1)))))
I would like to know whats the problem here and how I can fix it so it will compile, I cant find the mistake
In the 'else' part, you do something :: generic_map (...), which implies that generic_map would have to return a list instead of a generic_list.
Also, I don't see where you handle the seq case at all.
As a general note, I strongly suggest using pattern matching instead of if, List.hd and friends. In particular a comparison like lst = nil is always wrong, since it restricts the list to elements with equality type -- use pattern matching, or at least the List.null predicate.