Skip to content

Safe input handling #2254

Open
Open
@georgefst

Description

@georgefst

I have multiple applications in which I periodically load Dhall files, and need to safely handle any ill-formed input expression without bringing down the whole app. Essentially, I want a version of input that doesn't throw exceptions. AFAICT, the current API doesn't provide any easy way to do this. I've ended up with:

EDIT: The previous version of the code below was totally wrong as it attempted to use the type in place of the value. Also it required turning off the monomorphism restriction for printError, and had an unnecessary FromDhall constraint.

import Control.Exception
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Maybe
import Data.Either.Validation
import Data.Text (Text)
import Dhall qualified
import Dhall.Core qualified as Dhall
import Dhall.Import qualified as Dhall
import Dhall.Parser qualified as Dhall
import Dhall.TypeCheck qualified as Dhall

-- | Like 'Dhall.input', but handles any exceptions and prints them to stdout.
inputSafe :: Dhall.Decoder a -> Text -> IO (Maybe a)
inputSafe decoder =
    runMaybeT
        . ( printError . Dhall.toMonadic . Dhall.extract decoder . Dhall.renote . Dhall.normalize
                <=< checkType
                <=< printError
                <=< liftIO . try @(Dhall.SourcedException Dhall.MissingImports) . Dhall.load
                <=< printError . Dhall.exprFromText ""
          )
  where
    printError :: Show a => Either a b -> MaybeT IO b
    printError = either (\e -> liftIO (print e) >> mzero) pure
    checkType e = do
        expectedType <- printError . validationToEither $ Dhall.expected decoder
        _ <- printError . Dhall.typeOf $ Dhall.Annot e expectedType
        pure e

Is this even correct - are there other errors that could be thrown (I'm happy to treat IOException etc. separately)? Could the library export a function like this, or at least make it easier to construct? This took a lot of trial and error, and poring through documentation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    marshallingMarshalling between Dhall and Haskell

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions