I'm having trouble when trying to get a char from a string.
the code is:
let op = read_line () in
print_endline (op.[1]);
but when I try to compile it, the following message appears:
Error: This expression has type char but an expression was expected of
type
string
I also tried to put the result in a variable and print it later,
let op = read_line () in
let ch = op.[1] in
print_endline ch;
but I get the same error.
Ok, I find out why!
The 'print_endline' expect a string value, but the function 'String.[n]' returns a char.
I just changed the 'print_endline' for 'print_char' and it worked.
Related
I'm new to F#, apologies if I'm missing something obvious here.
I have the following code, with the intent to get user input and convert it to a uint:
let println ln =
printfn "%s" ln
let rec getUserKeyInput =
let x = System.Console.ReadKey()
string x
let getInputWithPrompt prompt =
println prompt
getUserKeyInput
let rec getUserUIntFromStr str =
try
let i = str |> uint
i
with
| :? System.FormatException -> println "Please enter a positive integer";
(getUserUIntFromStr (getUserKeyInput))
When getUserUIntFromStr is called with let i = getUserUIntFromStr str "Please enter a positive integer" is printed infinitely. I've also tried Console.ReadLine() and stdin.ReadLine(), both in interactive and from main, with the same results. It looks to me like none of the "Read" functions are waiting for input, but that doesn't seem right and I'm guessing I've done something wrong. Any suggestions?
getUserKeyInput is a value, not a function. It's evaluated only once at init time, not every time you reference it.
To make it a function, you need to give it a parameter. What type of parameter? Well, technically any type will do, but F# has you covered: for situations where you need to have some value, but there isn't a sensible value to use (which happens surprisingly often), there is a special type unit with a single value denoted as parentheses ():
let getUserKeyInput () =
let x = System.Console.ReadKey()
string x
(also note that rec is unnecessary, because the function isn't actually recursive)
(also note that ReadKey takes such parameter as well - it's the same deal there)
And then pass the parameter to call the function:
println "Please enter a positive integer"
getUserUIntFromStr (getUserKeyInput ())
I'm trying to convert Vec<&str> to Vec<u16> but I can't figure out a functional way to do it.
let foo: &str = "1,2,3"; // Parsing a string here
let bar: Vec<&str> = foo.split(",").collect(); // Bar is a nice vector of &str's
I need to get bar into a Vec<u16>.
There's an iterator adapter map! You'd use it like this:
let bar: Vec<u16> = foo.split(",").map(|x| x.parse::<u16>().unwrap()).collect();
parse is a library function that relies on the trait FromStr, and it can return an error, so we need to unwrap() the error type. (This is a good idea for a short example, but in real code, you will want to handle the error properly - if you have a value that's not a u16 there, your program will just crash).
map takes a closure that takes it's parameter by value and then returns the iterator obtained by lazily applying that function. You're collecting all of the values here, but if you only take(5) of them, you would only parse 5 of the strings.
You haven't fully specified your problem. Specifically, what should happen when one of the strings cannot be parsed into a number? When you parse a number from a string using parse, it can fail. That is why the function returns a Result:
fn parse<F>(&self) -> Result<F, F::Err>
where
F: FromStr,
Here's a solution that takes the vector, gets an iterator with iter, changes each item using map and ultimately returns a Result using collect. If the parsing was a success, you get an Ok. If any failed, you get an Err:
fn main() {
let input = "1,2,3";
let strings: Vec<_> = input.split(",").collect();
let numbers: Result<Vec<u16>, _> = strings.iter().map(|x| x.parse()).collect();
println!("{:?}", numbers);
}
Or you could remove failed conversions by filtering out Err values with flat_map:
fn main() {
let input = "1,2,3";
let strings: Vec<_> = input.split(",").collect();
let numbers: Vec<u16> = strings.iter().flat_map(|x| x.parse()).collect();
println!("{:?}", numbers);
}
Of course, it's a bit silly to convert the string into a vector of strings and then convert it again to a vector of integers. If you actually have a comma-separated string and want numbers, do it in one go:
fn main() {
let input = "1,2,3";
let numbers: Result<Vec<u16>, _> = input.split(",").map(|x| x.parse()).collect();
println!("{:?}", numbers);
}
See also:
Why does `Option` support `IntoIterator`?
My take as someone not really experienced in Rust yet.
fn main() {
let foo: &str = "1,2,3"; // Parsing a string here
let bar: Vec<&str> = foo.split(",").collect(); // Bar is a nice vector of &str's
// here the magic happens
let baz = bar.iter().map(|x| x.parse::<i64>());
for x in baz {
match x {
Ok(i) => println!("{}", i),
Err(_) => println!("parse failed"),
}
}
}
Note that since parse returns a Result, you have to extract the value from each parsed element. You might want to behave in a different way, e.g. filter only the succeeded results.
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.
I'm using the dgeev algorithm from the LAPACK implementation in the Accelerate framework to calculate eigenvectors and eigenvalues of a matrix. Sadly the LAPACK functions are not described in the Apple Documentation with a mere link to http://netlib.org/lapack/faq.html included.
If you look it up, you will find that the first two arguments in dgeev are characters signifying whether to calculate eigenvectors or not. In Swift, it is asking for UnsafeMutablePointer<Int8>. When I simply use "N", I get an error. The dgeev function and the error are described in the following screenshot
What should I do to solve this?
The "problem" is that the first two parameters are declared as char *
and not as const char *, even if the strings are not modified by the function:
int dgeev_(char *__jobvl, char *__jobvr, ...);
is mapped to Swift as
func dgeev_(__jobvl: UnsafeMutablePointer<Int8>, __jobvr: UnsafeMutablePointer<Int8>, ...) -> Int32;
A possible workaround is
let result = "N".withCString {
dgeev_(UnsafeMutablePointer($0), UnsafeMutablePointer($0), &N, ...)
}
Inside the block, $0 is a pointer to a NUL-terminated array of char with the
UTF-8 representation of the string.
Remark: dgeev_() does not modify the strings pointed to by the first two arguments,
so it "should be" declared as
int dgeev_(const char *__jobvl, const char *__jobvr, ...);
which would be mapped to Swift as
func dgeev_(__jobvl: UnsafePointer<Int8>, __jobvr: UnsafePointer<Int8>, ...) -> Int32;
and in that case you could simply call it as
let result = dgeev_("N", "N", &N, ...)
because Swift strings are converted to UnsafePointer<Int8>) automatically,
as explained in String value to UnsafePointer<UInt8> function parameter behavior.
It is ugly, but you can use:
let unsafePointerOfN = ("N" as NSString).UTF8String
var unsafeMutablePointerOfN: UnsafeMutablePointer<Int8> = UnsafeMutablePointer(unsafePointerOfN)
and use unsafeMutablePointerOfN as a parameter instead of "N".
With Swift 4.2 and 5 you can use this similar approach
let str = "string"
let unsafePointer = UnsafeMutablePointer<Int8>(mutating: (str as NSString).utf8String)
You can get the result from unsafePointer.
Using C++/QtDBus.
I'm trying to get a reply from DBus call to function described as:
object, dict PullAll(string targetfile, dict filters).
I registered (qDBusRegisterMetaType) a type defined as: typedef QPair< QDBusObjectPath, QVariantMap > Transfer;
In QDBusPendingCallWatcher handler I'm doing:
QDBusPendingReply<Transfer> reply = *pwatcher;
I get an error:
Unexpected reply signature: got "oa{sv}", expected "(oa{sv})"
What's wrong? What is parentheses in "(oa{sv})"?
I think the whole message needs to be wrapped in a struct. At least you have the proper signature otherwise and are getting a response.
arrays: []
dict entries: {}
structs: ()
I'm not that familiar with QtDbus, but looking at the page for the QDbusArgument Class, you might have to do something like this:
argument.beginStructure();
argument << mystruct.objectpath << mystruct.array;
argument.endStructure();