composewell / streamly

High performance, concurrent functional programming abstractions
https://streamly.composewell.com
Other
849 stars 63 forks source link

Beginner question on exception handling #2733

Closed realbogart closed 3 months ago

realbogart commented 3 months ago

Hello!

I just recently became aware of this cool library and now I'm trying to learn it by porting over some of my other haskell code to use streams. I got a bit stuck on how to handle exceptions.

Here is a code snippet:

scan input_paths _ = do
  files <-
    S.fromList input_paths
      & S.map Left
      & S.concatIterateBfs recurseDir
      & S.onException onDirException
      & S.handle dirException
      & S.filter isRight
      & S.map fromRight'
      & S.fold FL.toList
  mapM_ print files
  where
    recurseDir (Left path) = Just (SDir.readEitherPaths path)
    recurseDir (Right _) = Nothing
    onDirException = return $ Right "FOOOOOOOOOOOOOOOOOOOOOOOLE"
    dirException :: IOException -> IO (S.Stream IO (Either FilePath FilePath))
    dirException e = do
      print (show e)
      print "HELLO"
      return $ S.fromList [Right "wef", Right "wooof"]

This is the output:

"/mnt/vault/music_backup/#recycle: openDirStream: permission denied (Permission denied)"
"HELLO"
"wef"
"wooof"

This function is recursively listing the files/directories from a list of input directories. (I started from the ListDir example in the streamly-examples repo). I am trying to make it so that whenever the openDirStream exception is thrown, it should output some kind of "invalid" value to the stream. It does indeed ouput "wef" and "wooof" above but the stream is also closed and I don't get any of the other valid results. I also tried to get some output from onException but I can't get it to output anything and I don't know how it's supposed to work.

I am definitely misunderstanding how these functions are supposed to be used. Any help would be appreciated.

Using:

streamly ==0.10.0,
streamly-core ==0.2.1,

Thank you!

realbogart commented 3 months ago

Okay, I think that I managed to solve it on my own!

scan :: [FilePath] -> FilePath -> IO ()
scan input_paths _ = do
  files <-
    S.fromList input_paths
      & S.map Left
      & S.concatIterateBfs recurseDir
      & S.filter isRight
      & S.map fromRight'
      & S.fold FL.toList
  mapM_ print files
  where
    recurseDir (Left path) = Just (SDir.readEitherPaths path & S.onException onDirException & S.handle dirException)
    recurseDir (Right _) = Nothing
    onDirException :: IO ()
    onDirException = print "holymoly"
    dirException :: IOException -> IO (S.Stream IO (Either FilePath FilePath))
    dirException e = do
      print (show e)
      print "HELLO"
      return $ S.fromList [Right "wef", Right "wooof"]

The exception was caught on the wrong "level". And I also figured out onException. Closing the issue.

Really neat library!