我对purescript很新,我正在尝试效果和特殊的异步效果。
我最喜欢FP和严格的编译器之一,比如一个purescript,它强制你处理所有可能的结果,特别是当你定义某些东西可能失败时。例如,如果您使用的是Either,则需要告诉程序在遇到Right
答案或错误时该怎么做。
当我第一次看到效果时,我喜欢actions
和handlers
的概念,如果你的代码的一部分需要抛出异常(我想这是你想要使用的最后一个资源)你需要使用类似
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
(您没有访问权限)等错误。如果我想忽略特定的错误原因,只记录它失败了它是我的选择,但类型系统应该强制我处理它。
答案 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.readTextFile
为the async version。
表达式either e a
就是它发生的地方。由于Aff
有一个MonadError
,您唯一的办法就是抓住错误。也就是说,我完全同意你的观点,即效果应该暴露出可能抛出异常的事实。出于某种原因,只有the synchronous version的Node库可以。