Hello i am trying to do a incFirst function in ML. The function does the following: incFirst "bad" = "cad" incFirst "shin" = "thin". This is what i try to do fun incFirst s = chr(ord s + 1) ^ substring(s, 1, size s -1);
I get the following error: Can't unify string (In Basis) with char (In Basis)
(Different type constructors)
Found near chr (ord s + 1) ^ substring (s, 1, ... - ...)
Exception- Fail "Static Errors" raised
Any idea how i can concatenate a char with a string if the "^" operator is not working?
The operator is working, it's just that you can only concatenate strings,
and that ord operates on characters, not on strings.
(A character is not the same as a one-character string.)
You need to extract the first character and then convert the result to a string
fun incFirst s = String.str(chr (ord (String.sub (s,0)) + 1)) ^ substring(s, 1, size s - 1)
or you could take a detour through a list
fun incFirst s = let
fun inc (c::cs) = (chr(ord c + 1))::cs
in
implode (inc (explode s))
end
Related
I made a function that will find any digits in an array and remove them. Here's my code:
int noNums (char *a) {
int i;
int deleteInd;
for (i = 0; (i < MAX_NAME_SZ) && (a[i] != '\0'); i++) {
if ((a[i] >= '0') && (a[i] <= '9')) {
deleteInd = i;
memmove (&a[deleteInd], &a[deleteInd + 1], strlen (a) - deleteInd);
}
}
}
If a number is by itself in the char array, then it is removed, no problem. However, if there are consecutive numbers in the array, then only every other digit will be deleted?
If my char array has
w12345678
then the array is changed to
w2468
instead of
w
Any ideas?
After you do the memmove(), the next element is now in the index of the element you just deleted. But your loop will do i++, so you won't check that index again. As a result, whenever there are two digits in a row, you skip the second one.
One way to fix this is to loop from the end of the array to the beginning, instead of from the beginning to the end.
Another way is to do i-- after doing the memmove(), to counteract the i++ that the loop will do.
if (isdigit(a[i]) {
deleteInd = i;
memmove (&a[deleteInd], &a[deleteInd + 1], strlen (a) - deleteInd);
i--;
}
BTW, you should use isdigit() to test whether a character is a digit.
Have you noticed that you are deleting the first digit then skipping one?
When iterating through the array, you start at position 0 and incrementing. When you delete a digit, you alter the string index.
i = 0 (char = w)
Index: 012345689
string: w12345678
i = 1 (char = 1)
Index: 012345689
string: w2345678
i = 2 (char = 3)
Index: 012345689
string: w2345678
Essentially, you are shifting the string over whenever you delete your character.
Don't increment i when you delete a character.
Note that deleteInd is not needed in your code, you could use i directly.
This is not an answer — Barmar's is — but both this and OP's other question shows they could use a fresh look into how to modify character arrays in place.
This is written in the hopes that this is useful to others learning C as well.
Elements, or sequences of elements, can be removed from an array efficiently, using a simple loop over its contents.
The key is to keep two indexes: one for the next element (or elements) to be examined, and one for the last element stored (or the next position to store to).
For example, to remove digits in an array, one can use the following pseudocode function:
Function removedigits(array, length):
Let i = 0 # Index of next element to examine, "input"
Let o = 0 # Position of next element to store, "output"
While (i < length):
If (array[i] is not a digit):
Let array[o] = array[i]
Let o = o + 1
End If
Let i = i + 1
End While
# For a string, we'll also want to terminate the array
# at o, because the rest of it contains garbage (old contents):
Let array[o] = '\0'
End Function
When dealing with sequences, it may be useful to keep multiple indexes. For example, to remove duplicate lines, one might use the following function:
Function removeduplicatelines(array):
Let i = 0 # Next position in the array to be examined
Let o = 0 # Next position in the array to store to
Let ostarted = 0 # Index at which the last line stored started at
# Loop over each input line:
While (array[i] != '\0'):
# Find the length of this line. It can end with a newline
# or at the end of the string. The newline is not included.
Let ilen = 0
While (array[i + ilen] != '\n' && array[i + ilen] != '\0'):
Let ilen = ilen + 1
End While
# If the already stored line is of different length
# (the +1 is for the newline, as it is not included in ilen)
# or if it does not match the input line, store input line.
If (ostarted + ilen + 1 != o || memcmp(array + ostarted, array + i, ilen) != 0):
# The lengths or content differs. Store the line.
# Copy ilen characters, starting at array[i],
# to array[o] onwards.
# Because the array parts do not overlap,
# we can safely use memcpy() here.
memcpy(array + o, array + i, ilen)
# It is now the last stored line.
Let ostarted = o
Let o = o + ilen
# If there is a newline following the line,
# store that too.
If (array[i + ilen] == '\n'):
Let array[o] = '\n'
Let o = o + 1
End If
Else:
# It is the same line again. Do not store.
End If
# Proceed to the next input line.
Let i = i + ilen
# Because the newline was not included in ilen,
# skip it if there is one.
If (array[i] == '\n'):
Let i = i + 1
End If
End While
# After index o, the array may contain old contents;
# so terminate the string at index o.
Let array[o] = '\0'
End Function
Note that memcmp() returns zero, if the ilen characters starting at array + ostarted match those starting at array + i.
This approach works, if we know o never exceeds i; that is, that we never overwrite array contents we haven't examined yet. But do note that o is allowed to be equal to i, as that just means we overwrite the same character we just examined, making no actual change in the array.
If we wanted to modify the function so that it skips empty lines, we add a new while loop before the existing one, to remove any leading newlines:
While (array[i] == '\n'):
Let i = i + 1
End While
and, to remove any empty lines, we modify the last part within the while loop into
# Because the newline was not included in ilen,
# skip it (and any additional newlines) if there is one.
While (array[i] == '\n'):
Let i = i + 1
End While
Finally, do note that the above removeduplicatelines() is very careful about not appending a newline after the last line, if there isn't one in the array to begin with.
s = "this is a test string"
words = {}
for w in s:gmatch("%w+") do table.insert(words, w) end
Using this code I was able to separate each word but now I need to be able to access just the nth word. How could I print just the second word for example? could I convert it to an array somehow then use something similar to
print words[2]
Like this:
s = "this is a test string"
words = {}
for w in s:gmatch("%w+") do
table.insert(words, w)
end
print (words [2]) --> is
for k, v in ipairs (words) do
print (v)
end -- for
Apart from printing "is" it follows it by:
is
a
test
string
print words[2]
You can only omit the parentheses for string literals and table constructors, like:
print "hello, world"
print ( table.getn { "the", "quick", "brown", "fox" } ) --> 4
When I try to compile my ML Program ,I get an error saying:"Operator and Operand don't agree".
candidates.sml:78.8-78.40 Error: operator and operand don't agree [tycon mismatch]
operator domain: int * (int * 'Z * 'Y) list
operand: int * (int * real) list
in expression:
tr (n,candidates)
I understand the error but I can't find a solution.
The part of the code where I get the error is:
fun agonas fileName =
let
fun tr(n,[])=[]
| tr(n,((a,b,c)::d))=((n-a+1),b,c)::(tr(n,d))
val (n,l,candidates) = parse fileName
val cand = tr(n,candidates)
in
my_solution(l,cand)
end;
,where the candidates are related with the part below:
fun parse file =
let
(* a function to read an integer from an input stream *)
fun next_int input =
Option.valOf (TextIO.scanStream (Int.scan StringCvt.DEC) input)
(* a function to read a real that spans till the end of line *)
fun next_real input =
Option.valOf (TextIO.inputLine input)
(* open input file and read the two integers in the first line *)
val stream = TextIO.openIn file
val n = next_int stream
val l = next_int stream
val _ = TextIO.inputLine stream
(* a function to read the pair of integer & real in subsequent lines *)
fun scanner 0 acc = acc
| scanner i acc =
let
val d = next_int stream
val (SOME v) = Real.fromString (next_real stream)
in
scanner (i - 1) ((d, v) :: acc)
end
in
(n, l, rev(scanner n []))
end;
fun my_solution ( n , l ,candidates ) = [2 ,3 ,5 ,4 ,6]
fun agonas fileName = my_solution ( parse fileName )
I would appreciate it if you could find the mistake.Thanks in advance.
The problem is that parse, using scanner, builds a list of pairs — (int * real) list — while tr expects to get a list of triples — (int * 'Z * 'Y) list.
Not knowing what tr is supposed to do, the quick and dirty fix would be to change
tr(n,((a,b,c)::d))=((n-a+1),b,c)::(tr(n,d))
into
tr(n,((a,b)::d))=((n-a+1),b)::(tr(n,d))
But that may be the wrong solution - it depends on what the code is supposed to do.
(Sometimes it helps to explicitly write out the types yourself - even before writing the code - instead of relying on type inference to catch the places where you need to do some more thinking.)
The error message says it all: the offending line calls trans, and that is a function that expects two arguments, the second being a list of triples. However, you are passing it a list of pairs instead (as produced by your scanner function).
You didn't show us the trans function, so I cannot be more specific about what the appropriate fix would be.
In ML I have an array of chars! I am trying to find an array function in order to give the function the char #"T" and returns me the position of this element in array. I tried the find function and it doesn't work like that!
findi from the Array structure will do what you want. For an array of type 'a array, findi takes a (int * 'a) -> bool and a 'a array and returns an (int * 'a) option. So if you want to take a character and just return the character's position, you just need figure out the appropriate arguments to pass to findi and the appropriate way to interpret the result.
So for instance:
- fun findPos char = (Option.map (fn (i,_) => i)) o (Array.findi (fn (_,c) => c = char));
stdIn:2.65 Warning: calling polyEqual
val findPos = fn : ''a -> ''a array -> int option
- findPos #"c" (Array.fromList (explode "abcdef"));
val it = SOME 2 : int option
- findPos #"z" (Array.fromList (explode "abcdef"));
val it = NONE : int option
I try to find a library function in ML that equal to (cdr string) in Scheme (meaning (cdr abcd) = bcd).
(Asuming SML)
Another way is to convert the string to a list of chars (explode), then you have the option to take the head (hd) or tail (tl), and then finally convert it back to a string (implode):
- (implode o tl o explode) "this is a string";
val it = "his is a string" : string
The string conversion functions can be found in the String module, and the head and tail functions can be found in the List module
Obviously you can also use the substring method here, however in SML you have the extract function that are quite convenient in this case:
- String.extract("This is a string", 1, NONE);
val it = "his is a string" : string
Giving it the NONE argument makes it extract until the end of the string.
Assuming the Ocaml dialect, you could use the standard String module with e.g.
let rest_str str =
let slen = String.length str in
String.sub str 1 (slen-1)
;;