3
votes

I’m new to PureScript and trying to find the idiom for “assertion failure”. I use this commonly to halt execution when:

  • an invariant I need to rely on is broken
  • a branch of the code is unreachable
  • I want to defer the implementation of an expression but want that to “fail fast” at runtime (rather than just yield undefined)

In Haskell I would typically use the prelude function error for this kind of thing. In PureScript, I (naively) expected to be able to emulate error by throwing an exception and (unsafely) casting away the effect type, as below:

module Test.Test where

import Prelude
import Effect (Effect)
import Effect.Exception (throw)
import Unsafe.Coerce (unsafeCoerce)

main :: Effect Unit
main = do
   _ <- pure $ error "Doesn't fail"
   error' "Fails"

error :: ∀ a . String -> a
error = unsafeCoerce <<< throw

error' :: ∀ a . String -> Effect a
error' = throw

But this doesn't work: if I embed calls to error inside a large program, I end up with runtime objects with fields which are undefined (in the JavaScript sense), rather than a program which terminates abruptly as soon as error is executed. The function throw seems to do what I want, but it doesn't seem appropriate to pollute my program with the Effect type for the use cases above.

I don't object to PureScript's behaviour -- it seems reasonable that I can't cast an effectful computation to a pure one and still observe the effects. So I guess I'm missing a trick (or a library function that I haven't found yet). What's the PureScript idiom for what I'm looking for?

(The testing library purescript-assert provides assert functionality, but it too has type Effect Unit.)

1

1 Answers

4
votes

What you need is unsafePerformEffect - it will execute the effect in a transparent way and return its result as a pure value.

error :: forall a. String -> a
error = unsafePerformEffect <<< throw

Or, alternatively, it's very easy to FFI your own:

-- PureScript
foreign import error :: String -> a

// JS (foreign module)
exports.error = msg => throw new Error(msg)