如何使用purescript Aff

时间:2018-03-21 15:24:05

标签: purescript

我对purescript很新,我正在尝试效果和特殊的异步效果。

我最喜欢FP和严格的编译器之一,比如一个purescript,它强制你处理所有可能的结果,特别是当你定义某些东西可能失败时。例如,如果您使用的是Either,则需要告诉程序在遇到Right答案或错误时该怎么做。

当我第一次看到效果时,我喜欢actionshandlers的概念,如果你的代码的一部分需要抛出异常(我想这是你想要使用的最后一个资源)你需要使用类似

的东西来声明它
someAction :: forall eff. Eff (exception :: EXCEPTION | eff)

并且您可以定义一个删除该效果的处理程序,以便您知道从那时起您不必关心异常。

但是使用Aff monad和purescript-node-fs-aff库进行一些基本测试后,我得到了一些意想不到的结果。

如果我这样做

main :: forall e. Eff (console :: CONSOLE, buffer :: BUFFER, fs :: FS | e) Unit
main = do
  _ <- launchAff $ readAndLog "./non-existing-file" 
  pure unit

readAndLog :: forall eff. String -> Aff (fs :: FS, console :: CONSOLE | eff) Unit
readAndLog path = do
  str <- readTextFile UTF8 path
  log str

如果文件不存在,程序将终止抛出异常,并且没有任何告诉我此代码可能会失败,并且我应该尝试保护我的程序失败。

我实际上可以更加防守并使用catchError,但我期待至少编译器失败说我没有将异常视为可能的副作用。

main :: forall e. Eff (console :: CONSOLE, buffer :: BUFFER, fs :: FS | e) Unit
main = do
  _ <- launchAff $ readAndLog "./non-existing-file" `catchError` (\e -> log ("buu: " <> message e))
  pure unit

readAndLog :: forall eff. String -> Aff (fs :: FS, console :: CONSOLE | eff) Unit
readAndLog path = do
  str <- readTextFile UTF8 path
  log str

理想情况下,我想做Either之类的事情并负责处理操作可能带来的特定错误。例如,当我读取文件时,我应该会遇到ENOENT(文件不存在)或EACCES(您没有访问权限)等错误。如果我想忽略特定的错误原因,只记录它失败了它是我的选择,但类型系统应该强制我处理它。

2 个答案:

答案 0 :(得分:1)

您的问题有多个方面。

首先,效果行很快就会从标准练习中删除。这已经从v0.12开始了。关于这个问题,这里是a public opinion poll。讨论在GitHub上进行。简而言之:负担超过了收益。

然后存在知道可以抛出哪些异常的问题。如果您在任何地方使用第三方JavaScript,那将很困难。在这种情况下,我建议将已知异常视为可能抛出的所有异常的下限。换句话说,即使您捕获了所有已知的异常,您也必须使用默认捕获来解释未知。

看看Nathan Faubion的purescript-checked-exceptions图书馆。这显示了如何将已检查的异常应用于ExceptT接口。

我为JavaScript的本机异常做了类似的工作,适用于FFI。不幸的是,这还没有发布,但我希望很快能够这样做。至少你可以知道它是可能的。

最后一个方面是Aff本身。不幸的是,Aff不是为任意例外而设计的。它仅支持Error类型(即同名的JavaScript类型)。因此,最好使用Aff的purescript-checked-exceptions来添加已检查的异常。

答案 1 :(得分:0)

编译器不会告诉您,因为异常被您正在使用的库中的Aff机制所吸收。以下是相关部分:

readTextFile = toAff2 A.readTextFile
toAff2 f a b = toAff (f a b)
toAff p      = makeAff \e a -> p $ either e a

节点库中A.readTextFilethe async version

表达式either e a就是它发生的地方。由于Aff有一个MonadError,您唯一的办法就是抓住错误。也就是说,我完全同意你的观点,即效果应该暴露出可能抛出异常的事实。出于某种原因,只有the synchronous version的Node库可以。