The following Haskell program prompts the user for a password in the terminal and continues if he has entered the correct one:
main = do
putStrLn "Password:"
password <- getLine
case hash password `member` database of
False -> putStrLn "Unauthorized use!"
True -> do
...
Unfortunately, the password will appear on the screen as the user types it, which I want to avoid.
How can I read a sequence of characters that the users types without having the show up on the screen? What is the equivalent of getLine for this purpose?
I'm on MacOS X, but I would like this to work on Windows and Linux, too.
Do this:
module Main
where
import System.IO
import Control.Exception
main :: IO ()
main = getPassword >>= putStrLn . ("Entered: " ++)
getPassword :: IO String
getPassword = do
putStr "Password: "
hFlush stdout
pass <- withEcho False getLine
putChar '\n'
return pass
withEcho :: Bool -> IO a -> IO a
withEcho echo action = do
old <- hGetEcho stdin
bracket_ (hSetEcho stdin echo) (hSetEcho stdin old) action
There is a getPassword in System.Console.Haskeline. Probably it's an overkill for your case but someone may find it useful.
An example:
> runInputT defaultSettings $ do {p <- getPassword (Just '*') "pass:"; outputStrLn $ fromJust p}
pass:***
asd
It is possible to disable echoing in the terminal with the System.Posix.Terminal module. However, this requires POSIX support, so may not work on Windows (I didn't check).
import System.Posix.Terminal
import System.Posix.IO (stdInput)
getPassword :: IO String
getPassword = do
tc <- getTerminalAttributes stdInput
setTerminalAttributes stdInput (withoutMode tc EnableEcho) Immediately
password <- getLine
setTerminalAttributes stdInput tc Immediately
return password
main = do
putStrLn "Password:"
password <- getPassword
putStrLn "Name:"
name <- getLine
putStrLn $ "Your password is " ++ password ++ " and your name is " ++ name
Note that the stdin is line-buffered, so if you use putStr "Password:" instead of putStrLn, you need to flush the buffer first, otherwise the prompt will be inhibited also.
withEcho can be written with a little less noise:
withEcho :: Bool -> IO a -> IO a
withEcho echo action =
bracket (hGetEcho stdin)
(hSetEcho stdin)
(const $ hSetEcho stdin echo >> action)
As I commented above, I suggest you use haskeline, which is a full prompt library. I've used it happily for LambdaCalculator with no complaints.
I have found this useful when reading passwords:
import Control.Exception
import System.IO
withoutEcho :: IO a -> IO a
withoutEcho action =
finally (hSetEcho stdin False >> action) (hSetEcho stdin True)
Related
I am back again trying to learn Haskell and, oh boy it is difficult!
I am a trying to do a simple mongoDB insertion inside a Scotty endpoint. Problem is the type return by the insert function is not accepted in the Scotty do statement. The program is quite simple:
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Data.Monoid (mconcat)
import Control.Monad.Trans(liftIO,lift,MonadIO)
import System.IO
import Data.Text.Lazy.Encoding (decodeUtf8)
import Data.Text.Lazy (pack,unpack)
import Data.Maybe
import Data.Time.Clock.POSIX
import Database.MongoDB (Action, Document, Document, Value, access,
allCollections,insert, close, connect, delete, exclude, find,
host,findOne, insertMany, master, project, rest,
select, liftDB, sort, Val, at, (=:))
main :: IO ()
main = scotty 3000 $ do
post "/logs" $ do
id <- liftIO $ getTimeInMillis
b <- body
let decodedBody = unpack(decodeUtf8 b)
i <- liftIO $ insertLog id decodedBody
text $ "Ok"
--setup database connection
run::MonadIO m => Action m a -> m a
run action = do
pipe <- liftIO(connect $ host "127.0.0.1")
access pipe master "data" action
getTimeInMillis ::Integral b => IO b
getTimeInMillis = round `fmap` getPOSIXTime
insertLog::MonadIO m => Int -> String -> Action m Value
insertLog id body = run $ insert "logs" ["id" =: id, "content" =: body]
the problem comes in the line
i <- liftIO $ insertLog id decodedBody
And the type error is
Expected type: Web.Scotty.Internal.Types.ActionT
Data.Text.Internal.Lazy.Text IO Value
Actual type: Action m0 Value
Any help or tip will be welcome!
I see a different error message with that code. Maybe you made some changes (like adding liftIO).
• Couldn't match type ‘Control.Monad.Trans.Reader.ReaderT
Database.MongoDB.Query.MongoContext m0 Value’
with ‘IO a0’
Expected type: IO a0
Actual type: Action m0 Value
In the line:
i <- liftIO $ insertLog id decodedBody
the liftIO function expects a genuine IO action, of type IO a for some a. However, the expression insertLog id decodedBody doesn't represent an IO action. It is Mongo action of type Action m Value for some m that has a MonadIO constraint. You need to use some function run Mongo Action values in IO. It looks like you've already written such a function, named run. It's written for a general MonadIO m but can be specialized to:
run :: Action IO a -> IO a
so if you first run your Mongo action (to turn it into IO) and then lift that action (to run it in the Scotty action under post), the following should type check:
i <- liftIO $ run $ insertLog id decodedBody
Update: Whoops! I missed the run in the insertLog function. You either want to write:
-- use "run" here
main = do
...
i <- liftIO $ run $ insertLog id decodedBody
-- but no "run" here
insertLog::MonadIO m => Int -> String -> Action m Value
insertLog id body = insert "logs" ["id" =: id, "content" =: body]
OR you want to write:
-- no "run" here
main = do
...
i <- liftIO $ insertLog id decodedBody
-- change the type signature and use "run" here
insertLog :: Int -> String -> IO Value
insertLog id body = run $ insert "logs" ["id" =: id, "content" =: body]
That will avoid the double-run problem.
The reason run didn't work as intended in your original code is a little complicated...
The problem is that run has flexibility to convert its Mongo action to many possible monads by returning m a for any m that supports MonadIO m. Because you gave insertLog a type signature with return type MonadIO m' => Action m' Value (where I changed the variable to keep m and m' distinct), the type checker matched the return type of run to the return type of insertLog:
m a ~ Action m' Value
by setting a ~ Value and m ~ Action m'. So, your run in insertLog was actually used with the following bizarre type:
run :: Action (Action m') Value -> Action m' Value
Normally, this would have caused a type error, but the type of insert is also flexible. Instead of returning an action of type Action IO Value, which would be the "usual" type, it happily adapted itself to return an action of type Action (Action IO) Value to match what run was expecting.
I'm relatively new to Haskell, and this is my first time working with monad transformers. I'd really appreciate some help.
runQuery :: Pipe -> Query -> ActionM (Either Failure [Document])
runQuery pipe query = access pipe master "nutrition" (find query >>= rest)
main = do
pipe <- runIOE $ connect $ host "127.0.0.1"
scotty 3000 $ do
post "/" $ do
b <- body
let user :: Either String User = eitherDecode b
case user of
Left err -> text . pack $ "Could not decode the user:" ++ err ++ ":\n" ++ (show b)
Right u -> do
let query::Query = (select ["i_name" =: ["$in" =: map (unpack . name) (foods u)]] "stock_foods")
results <- runQuery pipe query
...
I'm trying to query a mongodb database under the scotty web framework, but I'm getting an error about MonadBaseControl. Do I really have to make an instance of this to connect to a database with scotty, and how would I go about doing it?
No instance for (MonadBaseControl
IO (scotty-0.7.2:Web.Scotty.Types.ActionT Text IO))
arising from a use of `find'
Possible fix:
add an instance declaration for
(MonadBaseControl
IO (scotty-0.7.2:Web.Scotty.Types.ActionT Text IO))
mongoDB is generic enough to work in any monad that is instance of MonadBaseControl IO and MonadIO.
For example, you can choose IO monad. In this case you need liftIO . runQuery inside scotty's action:
import Web.Scotty
import Database.MongoDB
import qualified Data.Text.Lazy as T
import Control.Monad.IO.Class
runQuery :: Pipe -> Query -> IO [Document]
runQuery pipe query = access pipe master "nutrition" (find query >>= rest)
main = do
pipe <- connect $ host "127.0.0.1"
scotty 3000 $ do
get "/" $ do
res <- liftIO $ runQuery pipe (select [] "stock_foods")
text $ T.pack $ show res
After #Sebastian Philipp added MonadBaseControl instance for Scotty.ActionT, there is no need to lift anything. You can transparently work with mongoDB form scotty. Just change type signature and drop liftIOs:
runQuery :: Pipe -> Query -> ActionM [Document]
...
get "/" $ do
res <- runQuery pipe (select [] "stock_foods")
text $ T.pack $ show res
Take this simple bit of code:
var line = "";
do {
println("Please enter a non-empty line: ")
line = readLine()
} while (line.isEmpty())
println("You entered a non-empty line: " + line)
It's definitely not particularly elegant, especially with the unfortunate scoping of line -- however, I think it's quite simple to read.
Now trying to translate this directly to scalaz effect, I have come up with:
def nonEmptyLine: IO[String] = for {
_ <- putStrLn("Please enter a non-empty line:")
line <- readLn
r <- if (line.isEmpty()) nonEmptyLine else IO(line)
} yield r
(for {
line <- nonEmptyLine
_ <- putStrLn("You entered a non-empty line: " + line)
} yield ()).unsafePerformIO
Which makes me feel like I'm missing something, as this doesn't feel like an improvement at all? Is there some higher order control flow stuff I'm missing?
You can make this (at least arguably) a lot prettier by skipping the for notation and using the combinators *> and >>= to pipe everything together:
import scalaz._, Scalaz._, effect._, IO._
val prompt = putStrLn("Please enter a non-empty line:")
def report(line: String) = putStrLn("You entered a non-empty line: " + line)
def nonEmptyLine: IO[String] = prompt *> readLn >>= (
(line: String) => if (line.isEmpty) nonEmptyLine else line.point[IO]
)
And then:
scala> (nonEmptyLine >>= report).unsafePerformIO
Please enter a non-empty line:
You entered a non-empty line: This is a test.
In general, though, I'm not sure you should expect code written using scalaz.effect to be more concise or easier to read than a straightforward imperative solution.
I am stuck with haskell types.
{-# LANGUAGE OverloadedStrings #-}
module Main (
main
) where
import qualified Facebook as FB
import Network.HTTP.Conduit (withManager)
import Control.Monad.IO.Class (liftIO)
import System.IO
app :: FB.Credentials
app = FB.Credentials "localhost" "249348058430770" "..."
url :: FB.RedirectUrl
url = "http://localhost/fb"
perms :: [FB.Permission]
perms = ["user_about_me", "email"]
main :: IO ()
main = do
fbAuthUrl <- FB.getUserAccessTokenStep1 url perms
liftIO $ print fbAuthUrl
argument <- readLn
token <- FB.getUserAccessTokenStep2 url [argument]
withManager $ \manager -> do
FB.runFacebookT app manager $ do
u <- FB.getUser "me" [] token
liftIO $ print (FB.userEmail u)
error
src/Main.hs:23:18:
Couldn't match expected type `IO t0'
with actual type `FB.FacebookT
FB.Auth m0 text-0.11.2.0:Data.Text.Internal.Text'
In the return type of a call of `FB.getUserAccessTokenStep1'
In a stmt of a 'do' block:
fbAuthUrl <- FB.getUserAccessTokenStep1 url perms
In the expression:
do { fbAuthUrl <- FB.getUserAccessTokenStep1 url perms;
liftIO $ print fbAuthUrl;
argument <- readLn;
token <- FB.getUserAccessTokenStep2 url [argument];
.... }
package http://hackage.haskell.org/package/fb
First, let me preface this answer by the disclaimer that I've never actually used the Facebook API or the Conduits library, so I'm not sure if this code actually does anything sensible, but by going with just the type information, I think this is what you were trying to do
main :: IO ()
main = withManager $ \manager -> FB.runFacebookT app manager $ do
fbAuthUrl <- FB.getUserAccessTokenStep1 url perms
liftIO $ print fbAuthUrl
argument <- liftIO $ readLn
token <- FB.getUserAccessTokenStep2 url [argument]
u <- FB.getUser "me" [] (Just token)
liftIO $ print (FB.userEmail u)
The main pitfall is that main in Haskell must always have the type IO a, but you are trying to use a value of type FacebookT Auth m () as your main. Your implementation is on the right track, but the runFacebookT and withManager need to be the first thing in the function.
Type-wise, the actual do-block has the type FacebookT Auth (ResourceT IO) (). The runFacebookT function is used to unwrap the FacebookT transformer, resulting in a ResourceT IO () value, which is in turn processed by withManager to produce a plain old IO ().
One additional problem was that you originally had a readLn in your do-block without liftIO, which was confusing the type-inference. I also added the missing Just to the FB.getUser call.
I have a form in which the user can either select from a pre-existing list of values, or create a new (Text) value.
What will be the most elegant way to code that?
My best (and IMO not so elegant) way of doing so was by defining:
data MyInput = MyInput {createNew :: Bool, newVal :: Maybe Text, existingVal :: Maybe Text}
myForm :: [(Text,Text)] -> Html -> MForm MySite MySite (FormResult MyInput,Widget)
myForm exisingVals = renderTable $ MyInput
<$> areq boolField "Create new" (Just False)
<*> aopt textField "New val" Nothing
<*> aopt (selectField existingVals) "Existing values" Nothing
And once the form is received, pass the result through something like:
getMyValue :: MyInput -> Either ErrorMsg Text
getMyValue i = if createNew i
then if newVal i == Nothing || existingVal i /= Nothing
then Left "Missing new value or illegal input"
else Right . fromJust . newVal $ i
else if existingVal i == Nothing || newVal i /= Nothing
then Left "Missing selection or illegal input"
else Right . fromJust . existingVal $ i
And have the handler decide whether to re-send the form, or proceed according to the result.
Any better/shorter suggestions?
My real form has two such select/create fields, which makes the data structure and processing even more tedious.
Thanks,
You can factor out the common code, use pattern matching and guards, and generalize with a higher-order-function that accepts the accessor functions:
import Control.Arrow ((&&&))
getVal isNew newVal oldVal i | isNew i = checkVal "new value" $ (newVal &&& oldVal) i
| otherwise = checkVal "selection" $ (oldVal &&& newVal) i
where checkVal _ (Just val, Nothing) = Right val
checkVal name _ = Left $ "Missing " ++ name ++ " or illegal input"
getMyVal = getVal createNew newVal existingVal