Есть ли способ использовать IO Bool в if-statement без привязки к имени в haskell?
Если у меня есть функция, которая возвращает IO Bool
(в частности, atomically
), есть ли способ использовать возвращаемое значение непосредственно в операторе if
без привязки?
Итак, в настоящее время у меня есть
ok <- atomically $ do
...
if (ok) then do
...
else do
...
Можно ли вообще написать это как-то вроде
if (*some_operator_here* atomically $ do
...) then do
...
else do
...
Я надеялся, что будет использовать анонимно что-то вроде <-
, т.е. if (<- atomically ...)
, но до сих пор нет такой удачи.
Аналогично, на getLine, можно ли написать что-то вроде
if ((*operator* getLine) == "1234") then do ...
Связанное дополнение - каков тип (<-)
? Я не могу заставить его появиться в ghci. Я предполагаю, что это m a -> a
, но тогда это означало бы, что его можно было бы использовать вне монады, чтобы избежать этой монады, которая была бы небезопасной, верно? Является ли (<-)
не функцией вообще?
Ответы
Ответ 1
Вы можете использовать ifM
от Control.Conditional
, если это соответствует вашей цели, и даже не сложно написать аналогичную функцию.
Просто, чтобы дать вам пример
import Control.Conditional
import Control.Monad
(==:) :: ( Eq a,Monad m) => m a -> m a -> m Bool
(==:) = liftM2 (==)
main = ifM (getLine ==: getLine) (print "hit") (print "miss")
Я думаю, что есть способы использования перепрошиваемого расширения синтаксиса, что вы даже можете использовать if c then e1 else e2
как синтаксис для ifM
, но не стоит пытаться это попробовать.
Ответ 2
С GHC 7.6 и расширением языка LambdaCase
вы можете написать
{-# LANGUAGE LambdaCase #-}
import System.Directory
main = do
doesFileExist "/etc/passwd" >>= \case
True -> putStrLn "Yes"
False -> putStrLn "No"
Это не совсем if..then..else
, но ближе, не требует привязки к результату, и некоторые люди (а не я) говорят, что if..then..else
- это плохой стиль в Haskell.
Ответ 3
Нет, вы не можете. Ну, честно говоря, есть "хак", который позволит вам хотя бы написать такой код и заставить его скомпилировать, но результаты почти наверняка не будут такими, какие вы хотели или ожидали.
Почему это невозможно? Ну, во-первых, значение типа IO Bool
ни в каком смысле не содержит значения типа Bool
. Скорее это "действие", которое при выполнении возвращает значение типа Bool
. С другой стороны, если бы это было возможно, это позволило бы вам скрывать побочные эффекты внутри того, что кажется чистым кодом. Это нарушит основной принцип Haskell. И Хаскелл очень принципиальный.