How to handle Effect failure?

I’m learning Purescript and I made the following program that

  • list file in a directory
  • for every file_name see if there is <file_name>/<file_name>.html files
  • make html <a> element to that file
  • log it
module Main
  (
   main
  )
  where

import Prelude

import Data.Array (filter, zip, fold)
import Data.String (joinWith)
import Data.Traversable (traverse)
import Data.Tuple (Tuple, fst, snd)
import Effect (Effect)
import Effect.Console (log)
import Node.FS.Sync (exists, readdir)

targetDir :: String
targetDir = "/Volumes/share/MarsSpace/"

filesExist :: Array String -> Effect (Array Boolean)
filesExist files =
  traverse (\a -> exists (targetDir <> a <> "/" <> a <> ".html") ) files

filterNotExisting :: Array (Tuple String Boolean) -> Array String
filterNotExisting a =
  a # filter snd # map fst

formatLink :: String -> String
formatLink s =
  fold ["<a src=\"", s, "\"</a>"]

main :: Effect Unit
main = do
  files <- readdir targetDir
  exists <- filesExist files

  (zip files exists)
    # filterNotExisting
    # map formatLink
    # joinWith "\n"
    # log

Currently files <- .. and exists <- ... lines could fail. So two questions.

  1. Does this program safer then JS counterpart where errors are unhandled?
  2. What is idiomatic way of handing Effects errors?
1 Like
  1. It’s safer in that you can expect errors only in the parts of your program that are typed with Effect. But no, if you’re using an Effect-typed function in PureScript that throws an error—either from PureScript or from the underlying API function it wraps—you still need to handle it if you want it handled…
  2. … with try. The idiom here isn’t much different from the advice I would expect to see in JavaScript: handle the error in the right place—not so deep that there’s no reasonable way to recover, and not so close to the top-level that you’re missing the context you’d need to recover usefully.

When you’ve learned more, you might find out about fancier error-handling patterns using ExceptT. That’ll be potentially useful when your program gets more abstract with the monad in which it’s operating, but the program you’ve provided is already specifically coupled to Effect, and for small programs there’s nothing wrong with that, so there’s no need to complexify things with a transformer stack.

1 Like

Thank you for the explanation and providing hints into more advance error handling.

I understood that a good practice would be to push all function with Effect on the boundary of a program however at the moment I don’t have enough knowledge to do that :slight_smile:

Yes try looks messy similar to JS.

Why people say that there could be no runtime failure with Purescript if functions like readdir can trough an exception that one might not catch?

I heard the claim with Elm before but I’d not make this claim with PureScript (or Elm either)

Someone saying that is either speaking about a limited set of run-time failures (for example, the sort of failures you can experience if passing an array to a function that expects a string) or misinformed.

Once upon a time, PureScript used Eff instead of Effect. Eff was a type that was parameterized by the sorts of effects you would need to handle, such as file IO, console IO, and exceptions, and users could handle them separately. It was a very cool idea, but the execution had a few usability issues, not least of which was that it required newcomers to PureScript like yourself to understand the details of row types (a moderately advanced topic) for writing even the simplest of programs.

So in 2017, PureScript changed to using one Effect type for the same sorts of things for which Haskell uses IO. This comes with the downside that once you’ve entered Effect you no longer know precisely which effects you’re dealing with.

If this saddens you, the spiritual successor to Eff lives on in purescript-run. It still requires the moderately-advanced knowledge of PureScript’s type system to use, and now additionally requires you to write (or compose! that’s the cool part!) an interpreter that adapts your algebraic effects to PureScript’s now-native Effects. It is still a very cool idea.

2 Likes

Thank you for clarification and a bit of history on the subject. This is very useful because I keep seeing Eff on random posts and get a bit confused.

I found this document useful for clarifying what Effect is.