Есть ли способ использовать IO Bool в if-statement без привязки к имени в haskell? - программирование
Подтвердить что ты не робот

Есть ли способ использовать 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, но тогда это означало бы, что его можно было бы использовать вне монады, чтобы избежать этой монады, которая была бы небезопасной, верно? Является ли (<-) не функцией вообще?

4b9b3361

Ответ 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. И Хаскелл очень принципиальный.