Error on type mismatch - functional-programming

I'm writing this function on SML. It is supposed to take a list of possible first name variations (my name is Victoria, so V, Vic, Vicky, etc.) and create records of {altname1, middle, last}, {alt2, middle, last}.
So here's my code:
fun similar_names (substits:, name) =
let
val {first=n1, second=n2, third=n3} = name
fun name_constructor (altnames:string list, acc) =
case altnames of
[] => acc
| a::aa => {first=a, second=n2, third=n3}::acc
in
name_constructor( get_substitutions2(substits, n1),name)
end
get_substitutions2 will just give a list of all the possible variations of a first name (ie: string list), and it works.
The error I'm getting is:
a02.sml:65.2-65.58 Error: operator and operand don't agree [tycon mismatch]
operator domain: string list * {first:string, second:'Z, third:'Y} list
operand: string list * {first:string, second:'Z, third:'Y}
in expression:
name_constructor (get_substitutions2 (substits,n1),name)
I don't understand why it's going between record list and record alone. Could you help?

name is only one record, but name_constructor expects acc to be a list (since you say ::acc).
Try
name_constructor(get_substitutions2(substits, n1), [name])

Related

SML: Value restriction error when recursively calling quicksort

I'm writing a quicksort function for an exercise. I already know of the 5-line functional quicksort; but I wanted to improve the partition by having it scan through the list once and return a pair of lists splitting the original list in half. So I wrote:
fun partition nil = (nil, nil)
| partition (pivot :: rest) =
let
fun part (lst, pivot, (lesseq, greater)) =
case lst of
[] => (lesseq, greater)
| (h::t) =>
if h <= pivot then part (t, pivot, (h :: lesseq, greater))
else part (t, pivot, (lesseq, h :: greater))
in
part (rest, pivot, ([pivot], []))
end;
This partitions well enough. It gives me a signature val partition = fn : int list -> int list * int list. It runs as expected.
It's when I use the quicksort below that things start to break.
fun quicksort_2 nil = nil
| quicksort_2 lst =
let
val (lesseq, greater) = partition lst
in
quicksort_2 lesseq # quicksort_2 greater
end;
I can run the above function if I eliminate the recursive calls to quicksort_2; but if I put them back in (to actually go and sort the thing), it will cease to run. The signature will be incorrect as well, giving me val quicksort_2 = fn : int list -> 'a list. The warning I receive when I call the function on a list is:
Warning: type vars not generalized because of value restriction are instantiated to dummy types (X1,X2,...)
What is the problem here? I'm not using any ref variables; the type annotation I've tried doesn't seem to help...
The main issue is that you're lacking the singleton list base case for your quicksort function. It ought to be
fun quicksort [ ] = [ ]
| quicksort [x] = [x]
| quicksort xs =
let
val (l, r) = partition xs
in
quicksort l # quicksort r
end
which should then have type int list -> int list given the type of your partition. We have to add this case as otherwise you'll never hit a base case and instead recurse indefinitely.
For some more detail on why you saw the issues you were having though:
The signature will be incorrect as well, giving me val quicksort_2 = fn : int list -> 'a list
This is because the codomain of your function was never restricted to be less general than 'a list. Taking a look at the possible branches in your original implementation we can see that in the nil branch you return nil (of most general type 'a list) and in the recursive case you get two 'a lists (per our assumptions thus far) and append them, resulting in an 'a list---this is fine so your type is not further restricted.
[Value Restriction Warning]
What is the problem here? I'm not using any ref variables
The value restriction isn't really related to refs (though can often arise when using them). Instead it is the prohibition that anything polymorphic at the top level must be a value by its syntax (and thus precludes the possibility that a computation is behind a type abstractor at the top level). Here it is because given xs : int list we (ignoring the value restriction) have quicksort_2 xs : 'a list---which would otherwise be polymorphic, but is not a syntactic value. Correspondingly it is value restricted.

(OCaml: non-exhaustive pattern matching

I have an OCaml function that returns the value of a specified cell in a table. The function works correctly but I still get a warning stating:
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
([],_)
even though I have in fact accounted for that value in my implementation here:
let cell_value([i;j],table) = match ([i;j],table) with
([],_) -> []
| (_,[]) -> []
| (_::_,_::_) -> List.nth (List.nth table (j-1)) (i-1);;
Like I said, the function returns the correct value, I'm just trying to get rid of the error. I'm still fairly new to OCaml, so any help would be greatly appreciated!
Contrary to what you might believe, the problem is not coming from the pattern-matching introduced by the match keyword but by another one you may not be aware of. Indeed, there is a pattern matching in the following fragment of your definition:
let cell_value ([i;j], table) = ...
because ([i; j], table) actually contains the pattern [i; j]. For this reason, this definition assumes that the first component of the pair given as argument to cell_value is a list containing exactly two elements. In other words, this definition is equivalent to:
let cell_value = function ([i; j], table) -> ...
or also to:
let cell_value x = match x with ([i; j], table) -> ...
Now, you probably understand the warning issued by the compiler: if you provide a value of the form ([], table) to your function, it will fail. The compiler is right:
# cell_value ([], []);;
Exception: Match_failure ("//toplevel//", 1, 14).

Standard ML: Truncating String

I know ML has a bunch of string methods (substring, etc) that would make this easier but I want to get more comfortable with the language, so I'm implementing some myself.
I'm trying to truncate a string, i.e. cut off the string after a certain number of characters. I think I'm very close but am getting a syntax error when I do
val x::xs = explode(myString);
Here's the full code:
fun getAllButLast([x]) = nil
| getAllButLast(x::xs) = x::getAllButLast(xs);
fun truncate(myString, 0) = ""
| truncate(myString, limit:int) =
let
val x::xs = explode(myString);
in
x::truncate(implode(getAllButLast(xs)), limit - 1)
end;
Thoughts on why the compiler doesn't like this?
val x::xs = explode(myString);
Thanks for the help,
bclayman
Edit to include error:
Ullman.sml:82.5-82.55 Error: operator and operand don't agree [tycon mismatch]
operator domain: char * char list
operand: char * string
in expression:
x :: truncate (implode (getAllButLast <exp>),limit - 1)
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
As the error message shows, it is complaining about a different line. And it is complaining because the right operand of the :: operator in that line (the result of the recursive call to truncate) is a string, not a list. You probably want to use ^ instead, which denotes string concatenation.
Hint: There are other issues with your code. At least it is extremely inefficient. You should generally avoid implode/explode, but if you must use them, you should at least only call each of them once for the whole string, and not once for every character in the recursion.

SML/NJ - linked list which can hold any types

I trying to create a datatype for linked list which can hold all types at same time i.e linked list of void* elements , the designing is to create a Node datatype which hold a record contains Value and Next .
What I did so far is -
datatype 'a anything = dummy of 'a ; (* suppose to hold any type (i.e void*) *)
datatype linkedList = Node of {Value:dummy, Next:linkedList}; (* Node contain this record *)
As you can see the above trying does not works out , but I believe my idea is clear enough , so what changes are required here to make it work ?
I am not sure if you are being forced to use a record type. Because otherwise I think it is simpler to do:
datatype 'a linkedlist = Empty | Cons of 'a * 'a linkedlist
Then you can use it somewhat like:
val jedis = Cons ("Obi-wan", Cons("Luke", Cons("Yoda", Cons("Anakin", Empty))));
I think the use of the record is a poor choice here. I cannot even think how I could represent an empty list with that approach.
-EDIT-
To answer your comment about supporting multiple types:
datatype polymorphic = N of int | S of string | B of bool
Cons(S("A"), Cons(N(5), Cons(N(6), Cons(B(true), Empty))));
Given the circumstances you may prefer SML lists instead:
S("A")::N(5)::N(6)::B(true)::[];
Which produces the list
[S "A",N 5,N 6,B true]
That is, a list of the same type (i.e. polymorphic), but this type is capable of containing different kinds of things through its multiple constructors.
FYI, if it is important that the types of your polymorphic list remain open, you can use SML's built-in exception type: exn. The exn type is open and can be extended anywhere in the program.
exception INT of int
exception STR of string
val xs = [STR "A", INT 5, INT 6] : exn list
You can case selectively on particular types as usual:
val inc_ints = List.map (fn INT i => INT (i + 1) | other => other)
And you can later extend the type without mention of its previous definition:
exception BOOL of bool
val ys = [STR "A", INT 5, INT 6, BOOL true] : exn list
Notice that you can put the construction of any exception in there (here the div-by-zero exception):
val zs = Div :: ys : exn list
That said, this (ab)use really has very few good use cases and you are generally better off with a closed sum type as explained by Edwin in the answer above.

Recursive List Creation Function. Errors in type

I have an Ocaml function that is giving me errors.
What I am trying to do:
Recursively create a List of random numbers (0-2) of size "limit".
Here's what I have:
let rec carDoorNumbers = fun limit ->
match limit with
| [1] -> Random.int 3
| [] -> Random.int 3 :: carDoorNumbers (limit-1);;
I am getting this error:
Error: This expression has type 'a list
but an expression was expected of type int
Think about what your function has to do: given a limit, you have to create a list of numbers. So your type is something like carDoorNumbers : int -> int list.
Looking at that, it seems you have two errors. First, you're matching limit (which should be an int) against a list pattern. [1] -> ... matches a list containing only the element 1 and [] matches the empty list; you really want to match against the number 1 and any other number n.
The second error is that you return two different types in your match statement. Remember that you are supposed to be returning a list. In the first case, you are returning Random.int 3, which is an int rather than an int list. What you really want to return here is something like [Random.int 3].
The error you got is a little confusing. Since the first thing you returned was an int, it expects your second thing to also be an int. However, your second case was actually correct: you do return an int list! However, the compiler does not know what you meant, so its error is backwards; rather than changing the int list to an int, you need to change the int to an int list.
Your match expression treats limit like a list. Both [1] and [] are lists. That's what the compiler is telling you. But it seems limit should be an integer.
To match an integer, just use an integer constant. No square brackets.
(As a side comment, you might want to be sure the function works well when you pass it 0.)

Resources