Как избежать подъема в MaybeT и почему финальная валидация неэффективна?

Как мы можем избежать - если это имеет смысл - использования lift в MaybeT?

Классический пример из викикниг.

Данный

isValid :: String -> Bool
isValid s = length s >= 8
            && any isAlpha s
            && any isNumber s
            && any isPunctuation s

У нас есть

getPassphrase :: MaybeT IO String
getPassphrase = do s <- lift getLine
                   guard (isValid s) -- Alternative provides guard.
                   return s

askPassphrase :: MaybeT IO ()
askPassphrase = do lift $ putStrLn "Insert your new passphrase:"
                   value <- getPassphrase
                   lift $ putStrLn "Storing in database..."

Что я пробовал

Думаю, мне нужно использовать ask и tell, поэтому я преобразовал код следующим образом:

getPassphrase :: MaybeT (ReaderT String IO) String
getPassphrase = do 
        s <- ask
        guard (isValid s) -- Alternative provides guard.
        return s

askPassphrase :: MaybeT (ReaderT String IO) ()
askPassphrase = do 
  -- _ <- tell "Insert your new passphrase:"
  value <-  getPassphrase
  -- _ <- tell "Storing in database..."
  return ()



main :: IO (Maybe ())
main =
  runReaderT (runMaybeT askPassphrase) "test123!"

Строка "test123!" возвращает Just(), а "test123" возвращает Nothing, так что IMO работает, как и ожидалось, но мне все равно нужно включить Writer.

If I do

askPassphrase :: MaybeT (ReaderT String (WriterT String IO)) ()
askPassphrase = do 
  _ <- tell "Insert your new passphrase:"
  let value =  getPassphrase
  _ <- tell "Storing in database..."
  return ()



main :: IO ()
main =
  execWriterT (runReaderT (runMaybeT askPassphrase) "test123!") >>= putStrLn

он компилируется и запускается, но что-то идет не так, потому что любая строка считается допустимой, я имею в виду, что я всегда вижу "Insert your new passphrase:Storing in database..." в выводе. Что мне не хватает?


person Giulio    schedule 08.01.2020    source источник


Ответы (1)


Мне просто нужно было найти правильные типы моих функций с помощью команды :t, а затем указать их, они

getPassphrase :: MaybeT (ReaderT String (WriterT String IO)) [Char]
getPassphrase = do

а также

askPassphrase :: MaybeT (ReaderT String (WriterT String IO)) ()
askPassphrase = do 

И liftможно избежать! (ask уже было без lift во второй части вопроса)

askPassphrase = do 
  tell "Insert your new passphrase:"
  value <-  getPassphrase
  tell "Storing in database..."

Онлайн-версия здесь.

person Giulio    schedule 08.01.2020