Last active
July 11, 2020 02:25
-
-
Save willowell/fe7ee35e8069661523331276a6cb50c9 to your computer and use it in GitHub Desktop.
trouble translating Haskell functions to Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The Haskell functions I am trying to translate: | |
promptLine :: String -> IO String | |
promptLine msg = do | |
putStr msg | |
hFlush stdout | |
getLine | |
input :: Read a => String -> (a -> Bool) -> IO a | |
input msg validator = do | |
str <- promptLine msg | |
case (readMaybe :: Read a => String -> Maybe a) str of | |
Just x -> case validator x of | |
True -> return x | |
False -> do | |
putStrLn "Invalid input." | |
input msg validator | |
Nothing -> do | |
putStrLn "Invalid input." | |
input msg validator | |
------------------------------------------------------------------------- | |
What I have so far in Rust: | |
// I am deliberately using Option rather than Result here because | |
// I only need to worry about the type Option is holding and because | |
// Option and Result are both monads, so I figure my logic and function chaining should hold. | |
// Once these work with Option, I'm going to move them over to Result. | |
fn prompt_maybe(msg: &str) -> Option<String> { | |
use std::io::Write; | |
print!("{}", msg); | |
// Force output to stdout before reading from stdin | |
match std::io::stdout().flush() { | |
Ok(()) => (), | |
Err(_) => return None | |
} | |
let mut buffer: String = String::new(); | |
match std::io::stdin().read_line(&mut buffer) { | |
Ok(_) => (), | |
Err(_) => return None | |
} | |
Some(buffer.trim_end().to_owned()) | |
} | |
// readMaybe :: Read a => String -> Maybe a | |
fn read_maybe<T>(arg: &str) -> Option<T> where T: std::str::FromStr { | |
match arg.parse::<T>() { | |
Ok(res) => Some(res), | |
Err(_) => None | |
} | |
} | |
// If I can compose prompt_maybe() and read_maybe(), then I can translate the input function I have in my Haskell code. | |
// For reference, I *was* able to achieve something similar using the promptly crate: | |
use promptly::{prompt, Promptable}; | |
fn input<T, F>(msg: &str, validator: F) -> T | |
where | |
T: Copy + std::default::Default + Promptable, F: Fn(T) -> bool, | |
{ | |
loop { | |
let x = prompt::<T, &str>(msg).unwrap_or_default(); | |
if validator(x) { | |
break x; | |
} else { | |
println!("Invalid input. Please try again."); | |
} | |
} | |
} | |
fn main() { | |
let s2 = prompt_maybe("What's your favourite number? "); | |
match s2 { | |
Some(s2) => println!("You entered: '{}'", s2), | |
None => println!("Hmm...") | |
} | |
let x2 = s2.and_then(read_maybe::<i64>); // <-- Error is thrown from this call to read_maybe() | |
match x2 { | |
Some(x2) => println!("You entered: '{}'", x2), | |
None => println!("Hmm...") | |
} | |
} | |
---------------------------------------------------------------------------- | |
Error details: | |
--> src/main.rs:76:26 | |
| | |
45 | fn read_maybe<T>(arg: &str) -> Option<T> where T: std::str::FromStr { | |
| ------------------------------------------------------------------- found signature of `for<'r> fn(&'r str) -> _` | |
... | |
76 | let x2 = s2.and_then(read_maybe::<i64>); | |
| ^^^^^^^^^^^^^^^^^ expected signature of `fn(std::string::String) -> _` | |
// I don't understand this error because I thought one could pass a String where a &str is expected. | |
// However, the error goes away if I change `fn read_maybe<T>(arg: &str)` to `fn read_maybe<T>(arg: String)` | |
// and accordingly change `match s2` to `match &s2` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment