ERROR: String list list instead of string list - sml

I have this function that results a string list:
fun get_substitutions1 ([],_) = []
| get_substitutions1 (x::xs,s) = case all_except_option(s,x) of
NONE => [] #get_substitutions1(xs,s)
| SOME lst => lst #get_substitutions1(xs,s)
And this function that takes a string list list and a type:
fun similar_names(slist,full_name:{first:string,middle:string,last:string})=
let
fun aux(slist,acc)=
case full_name of
{first=a,middle=b,last=c} => case get_substitutions1(slist,a) of
[] => full_name::acc
| x::xs' => full_name:: aux(xs',{first=x,middle=b,last=c}::acc)
in aux(slist,[])
end
And i get an error:
Error: operator and operand don't agree.
operator domain: string list list *
{first:string, last:string, middle:string} list
operand: string list *
{first:string, last:string, middle:string} list
in expression:
aux (xs',{first=x,middle=b,last=c} :: acc)
Is there any other way?

Well first of all you might wan't to indent your code so that it is readable.
It is quite obvious why you get the error you do. The function
fun get_substitutions1 ([],_) = []
| get_substitutions1 (x::xs,s) =
case all_except_option(s,x) of
NONE => []#get_substitutions1(xs,s)
| SOME lst => lst #get_substitutions1(xs,s)
has the type
val get_substitutions1 = fn : ''a list list * ''a -> ''a list
and you are trying to use the result of this function in your inner case expression where you take the tail of the returned list (type 'a list) and use them in the recursive function call.
fun similar_names(slist,full_name:{first:string,middle:string,last:string})=
let
fun aux(slist,acc)=
case full_name of
{first=a,middle=b,last=c} =>
case get_substitutions1(slist,a) of
[] => full_name::acc
| x::xs' => full_name:: aux(xs',{first=x,middle=b,last=c}::acc)
in aux(slist,[])
end
However since your first argument of aux is used in get_substitutions1, that argument must be of type 'a list list, but the xs' you use down in the recursive call is only of type 'a list.

Related

List.assoc using List.find

I want to implement the List.assoc function using List.find, this is what I have tried:
let rec assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> try (List.find (fun x -> a = x) lista)
b
with Not_found -> assoc l x;;
but it gives me this error:
This expression has type ('a * 'b) list but an expression was expected of type 'a list
The type variable 'a occurs inside 'a * 'b
I don't know if this is something expected to happen or if I'm doing something wrong. I also tried this as an alternative:
let assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> match List.split lista with
| (l1,l2) -> let ind = find l1 (List.find (fun s -> compare a x = 0))
in List.nth l2 ind;;
where find is a function that returns the index of the element requested:
let rec find lst x =
match lst with
| [] -> raise Not_found
| h :: t -> if x = h then 0 else 1 + find t x;;
with this code the problem is that the function should have type ('a * 'b) list -> 'a -> 'b, but instead it's (('a list -> 'a) * 'b) list -> ('a list -> 'a) -> 'b, so when I try
assoc [(1,a);(2,b);(3,c)] 2;;
I get:
This expression has type int but an expression was expected of type
'a list -> 'a (refering to the first element of the pair inside the list)
I don't understand why I don't get the expected function type.
First off, a quick suggestion on making your assoc function more idiomatic OCaml: have it take the list as the last argument.
Secondly, why are you attempting to implement this in terms of find? It's much easier without.
let rec assoc x lista =
match lista with
| [] -> raise Not_found
| (a, b) :: xs -> if a = x then b else assoc x xs
Something like this is simpler and substantially more efficient with the way lists work in OCaml.
Having the list as the last argument, even means we can write this more tersely.
let rec assoc x =
function
| [] -> raise Not_found
| (a, b) :: xs -> if a = x then b else assoc x xs
As to your question, OCaml infers the types of functions from how they're used.
find l1 (List.find (fun s -> compare a x = 0))
We know l1 is an int list. So we must be trying to find it in an int list list. So:
List.find (fun s -> compare a x = 0)
Must return an int list list. It's a mess. Try rethinking your function and you'll end up with something much easier to reason about.

Why is there a type error when using List.fold_left return value?

I am trying to use the list returned from List.fold_left on a list of type pExp (user-defined type). The purpose of this is to create a list of Times (pExp list) with the list matched in a Plus l type.
let eval (lst: pExp list): pExp list =
match lst with
| [] -> []
| other patterns
| Plus l::t -> (List.fold_left (fun acc a -> Times(a::t)::acc) lst)
(* For each item a in l, append it to t and make it a Times *)
| _ -> []
I expected List.fold_left to return a pExp list, but I get this error.
Error: This expression has type pExp list -> pExp list
but an expression was expected of type pExp list
The first line in the error message indicates fold_left returns a pExp which is exactly what is expects, no?
This expression:
(List.fold_left (fun acc a -> Times(a::t)::acc) lst)
has a function type. List.fold_left takes 3 arguments, and you're only passing it 2 here.
The compiler is saying that you're supplying a function type (pExp list -> pExp list) where a non-function type (pExp list) was expected. And that's indeed the problem.
Most likely you left out the initial value between the function and lst.

ocaml 'a list list function tuples

let sample_table4 = [
[["11"];["21"];["31"];["41"]];
[["12"];["22"];["32"]];
[["13"];["23"]];
[["14"]]];;
This is where I'm stuck with writing a function to get one of these numbers
let tgvc (pos, table) =
match pos with
|[] -> []
|i::[j] -> List.nth (List.nth table (j-1)) (i-1)
|i::_ -> []
;;
val tgvc : int list * 'a list list list -> 'a list = <fun>
I'm supposed to get this signature
tgvc ([3;2],sample_table4);;
val tgvc : int list * ’a list list -> ’a = <fun>
-: string list = ["32"]
What's missing in the function?
I'm sure it has to be recursive now.
Even though it computes the right answer, it's not the right method. The ->[ ] is what's getting me
let rec tgvc (pos, table) = function
|_,[] -> []
|[i;1], h::_ -> List.nth h (i-1)
|[i;j], _::t -> tgvc ([i;j-1], t)
|_ -> []
|[i;j], _::t -> tgvc ([i;j-1], t)
^^^^^^^^^^^^^^^^^
Error: This expression has type int list * 'a list list list -> 'a list
but an expression was expected of type 'a list
What's missing in the function?
A lot of things. Your function simply returns one of many lists of initial input. You don't even use i indice.
I suggest you to think what your function need to do for the given input:
[i; 1], h::_ - you are "in front" of the desirable list
[i; j], _::t - not desirable list yet (some recursion maybe?)
_, [] - empty table
_ - everything else
Edit
You have two problems with your last implementation. First of all in your first and last branches you return [], I guess you would like to exit with an error, so you can throw an exception (via failwith for example). The second problem is actually in the first line: get_table_values_cell (pos, table) = function, it means that you define get_table_values_cell as function with two arguments, you give one explicitly ((pos, table)) and the second is introduced by function keyword. So all you need is to pick only one: get_table_values_cell = function

Quicksort in SML operator and operand don't agree error

I am trying to write a quicksort function of type
'a list * ('a * 'a -> bool) -> 'a list
but for some reason I am getting:
'a list -> ('a * 'a -> bool) -> 'a list
Here is my code for the function:
fun quicksort xs f = let
fun qs [] = []
| qs [x] = [x]
| qs (p::xs) = let
val (less, more) = List.partition (fn x => f (x, p)) xs
in
qs less # p :: qs more
end
in
qs xs
end
When I call the function I get this error:
stdIn:73.1-73.18 Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z list
operand: int list * (int * int -> bool)
in expression:
quicksort (L, op <)
I realize that I must be passing it in wrong, but I just can't see my mistake. So, my question is what is going on here in which I get this error while trying to pass in my list and operator?
You could simple change:
fun quicksort xs f = let
to:
fun quicksort (xs,f) = let
since you want quicksort to have as parameters a tuple (xs,f).

right-hand-side of clause doesn't agree with function result type

Write a function remove_option, which takes a string and a string list. Return NONE if the string is not in the list, else return SOME xs where xs is identical to the argument list except the string is not in it. You may assume the string is in the list at most once. Use same_string, provided to you, to compare strings. Sample solution is around 8 lines.
The function type should be fn : string * string list -> string list option.Here is my code
fun same_string(s1 : string, s2 : string) =
s1 = s2
fun remove_option (str: string ,str_list : string list) =
case str_list of
[] => NONE
| x::xs => if same_string(x,str)
then SOME xs
else x :: remove_option( str,xs)
and the error report
hw2provided.sml:10.5-15.37 Error: right-hand-side of clause doesn't agree with f
unction result type [tycon mismatch]
expression: _ option
result type: string list
in declaration:
remove_option =
(fn (<pat> : string,<pat> : string list) =>
(case str_list
of <pat> => <exp>
| <pat> => <exp>))
uncaught exception Error
raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:292.17-292.20
So where is the bug ?
The problem is that you want to return a string list option but the line
else x :: remove_option( str,xs)
makes it seem that you want to return a string list
What you need to do with the return value of remove_option( str,xs) is
1) decide what to do if it is NONE
2) extract the string list strings (or whatever you want to call it) if it is of the form SOME strings, tack x onto the front of the list, and repackage it with SOME before returning it.
You seem comfortable with the use of case, so you could use it here.
Since John showed where the bug is, here are some extra comments:
Since the function same_string is not injected, it is superfluous. You might as well use =.
Recursive functions that return 'a option are kind of tricky, since you need to unpack the result:
fun remove_option (s1, []) = NONE
| remove_option (s1, s2::ss) =
if s1 = s2
then SOME ss
else case remove_option (s1, ss) of
NONE => NONE
| SOME ss' => SOME (s2::ss')
Generally, when you see the pattern
case x_opt of
NONE => NONE
| SOME x => SOME (f x))
this can be refactored into using e.g. Option.map : ('a -> 'b) -> 'a option -> 'b option:
Option.map f x_opt
In this case,
fun curry f x y = f (x, y)
fun remove_option (s1, []) = NONE
| remove_option (s1, s2::ss) =
if s1 = s2
then SOME ss
else Option.map (curry op:: s2) (remove_option (s1, ss))
where curry op:: s2, the function that puts s2 in front of a list.