Можно ли выйти из функции в Haskell с ее текущим типом возврата? - PullRequest
3 голосов
/ 04 ноября 2019

Возможно ли иметь функцию, которая возвращает Int, чтобы закрыть программу при ошибке? Например, и выйти с выбранным значением?
Вот мой код:

example :: String -> Int
example s = do
let j = read  s
case j of
    0 -> j
    _ -> exitWith (exitFailure: 84)

Я просто хочу остановить программу из-за ошибки в функции, которая не является IO, и я не могу найти способ, но использую функцию «error», который не возвращает никакого значения.

Ответы [ 2 ]

2 голосов
/ 04 ноября 2019

Вот альтернатива, использующая исключения.

Сначала мы объявляем пользовательский тип исключения, содержащий наш ExitCode

import Control.Exception
import System.Exit

data TerminationException = TE ExitCode
   deriving Show

instance Exception TerminationException where

Затем мы можем использовать его в чистом коде, бросаяисключение по мере необходимости.

example :: String -> Int
example s = let
   j = read s
   in case j of
      0 -> j
      _ -> throw (TE (ExitFailure 84))

Обратите внимание, что вышеприведенный read приведет к аварийному завершению программы, если входная строка не проанализирует число. Я включил это только для того, чтобы быть как можно ближе к исходному коду, но вместо этого было бы лучше использовать readMaybe или reads.

Затем мы можем определить небольшой обработчик исключений.

withExit :: IO a -> IO a
withExit action = action `catch` (\(TE code) -> exitWith code) 

Наконец, нам нужно обернуть main с помощью нашего обработчика следующим образом.

main :: IO ()
main = withExit $ do
   putStrLn "hello 1"
   print (example "0")  -- passes
   putStrLn "hello 2"
   print (example "1")  -- ** --
   putStrLn "hello 3"

Вышеуказанное main вызывает исключение в строке, отмеченной **,Там ничего не print ed и программа закрывается с кодом возврата 84, как указано в example.

2 голосов
/ 04 ноября 2019

Опция, как сказано в комментариях, может быть:

example :: String -> Maybe Int
example s = do
let j = read s
case j of
    0 -> Just j
    _ -> Nothing

, и затем, когда вы ее используете, вы можете сопоставить шаблон со значением Maybe. Это не то же самое, что «выйти из программы». Но это способ справиться с ошибкой.

Другой способ - с Either

type ErrorMsg = String 

example :: String -> Either ErrorMsg Int
example s = do
let j = read s
case j of
    0 -> Right j
    _ -> Left "exitFailure: 84"
...