Monday, November 14, 2022

[FIXED] How to pattern match for a True/False within a function in Haskell?

Issue

I am trying to handle file errors manually so I can print my own message and currently I have this code:

handleFileError :: FileError -> IO a
handleFileError (FileError errorKind) = do
  case errorKind of
    NotFound -> undefined
    NoPermission -> undefined
    IsDirectory -> undefined

fileRead :: String -> IO String
fileRead file = do
  pathExists <- doesPathExist file
  notDirectory <- doesFileExist file

  -- These two must be handled before `System.Directory.getPermissions` is called
  -- or else it will error.

  permissions <- getPermissions file
  let hasReadPermissions = readable permissions

  if hasReadPermissions then undefined -- This is the success case
  else handleFileError $ FileError NoPermissions

I would like to check if any of the 3 booleans (pathExists, notDirectory, and hasReadPermissions) are false, and then act accordingly. I tried to implement this using a case with False, however this just always runs the first branch.


Solution

One way would be to use MultiWayIf:

do
  pathExists <- doesPathExist file
  notDirectory <- doesFileExist file
  permissions <- unsafeInterleaveIO (getPermissions file)
  if
    | not pathExists -> -- ...
    | not notDirectory -> -- ...
    | not permissions -> -- ...
    | otherwise -> -- ...

If you're allergic to extensions, the old-fashioned way to get this feature is using guards, as in:

  case () of
    _ | not pathExists -> -- ...
      | not notDirectory -> -- ...
      | not permissions -> -- ...
      | otherwise -> -- ...

But I recommend neither of these. Instead, just do something with the file, and catch the exception; otherwise there are race conditions with the file system changing out from under you between the check and the file use. Like this:

fileRead :: String -> IO String
fileRead = catch (undefined {- success case -}) $ \e -> if
  | isDoesNotExistError e -> -- ...
  | isPermissionError e -> -- ...
  | otherwise -> throw e


Answered By - Daniel Wagner
Answer Checked By - Clifford M. (PHPFixing Volunteer)

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.