[英]How do you understand error messages in Purescript?
我正在使用 Purescript 构建一个加密货币套利机器人,主要是为了了解函数式编程范例。 作为主要的 JS 程序员,我发现 Purescript 的错误消息很难解释。 目前,在尝试使用 Affjax 库发出 http 请求时,我遇到了“TypesDoNotUnify”错误。 我的代码如下所示:
import Affjax.ResponseFormat (ResponseFormat(..))
import Affjax.ResponseFormat as ResponseFormat
import Data.Argonaut.Core (Json, fromString, stringify)
import Data.Either (Either(..))
import Data.HTTP.Method (Method(..))
import Effect (Effect)
import Effect.Aff (Aff, launchAff_)
import Effect.Console (log)
import Node.Express.App (App, listenHttp, get)
import Node.Express.Response (send)
import Node.HTTP (Server)
import Node.HTTP.Client (method)
makeQuoteRequest :: String -> String -> String -> String
makeQuoteRequest fromAddress toAddress amount = "https://api.1inch.exchange/v3.0/137/quote?fromTokenAddress=" <> fromAddress <> "&toTokenAddress=" <> toAddress <> "&amount=" <> amount
sendQuoteRequest :: Either Error Unit
sendQuoteRequest = launchAff_ do
result <- AX.request(AX.defaultRequest {
url = makeQuoteRequest "0xd6df932a45c0f255f85145f286ea0b292b21c90b" "0xc2132d05d31c914a87c6611c10748aeb04b58e8f" "1000000000000000000"
,method = Left GET
,responseFormat = ResponseFormat.json
})
case result of
Left err -> log $ "Quote failed: " <> AX.printError err
Right response -> log $ "GET /api response: " <> stringify response.body
app :: App
app = do
get "/" $ send "<a href='http://localhost:8080/quotes'><button>Get Quotes</button></a>"
get "/quotes" $ send "This is where your quotes should go"
main :: Effect Server
main = do
listenHttp app 8080 \_ ->
log $ "Listening on " <> show 8080
VsCode 突出显示以Left err -> log
开头的行作为问题的根源,当我 hover 超过该错误时,我得到以下附加信息:
printError:: 错误 → 字符串无法匹配类型
影响
与类型
阿夫
在尝试将类型 Effect Unit 与类型 Aff t0 匹配时同时检查表达式(应用日志)((附加“Quote failed:”)(printError err))在值声明 sendQuoteRequest 中具有类型 Aff t0
其中 t0 是未知类型 PureScript(TypesDoNotUnify)
我希望了解的不仅是如何修复这个错误,而是更多地了解如何解释 Purescript 给我的错误。 如果您的代码中出现此错误,您将采取什么步骤来解决它?
错误消息中的第一句话是:
无法将类型
Effect
与类型Aff
匹配
然后它澄清了一点:
在尝试将类型
Effect Unit
与类型Aff t0
匹配时
这就是绝大多数类型错误的样子。 这意味着编译器一直在跟踪您的程序,找出哪些位具有哪些类型,并最终找到一个位,从一行推理中得出的类型为Effect Unit
,但从另一行推理中得出的类型为Aff t0
(对于一些未知的类型t0
)。 两行推理都是正确的,但它们的结果不匹配,因此编译器不知道下一步该做什么。
你问的那些推理是什么? 好吧,编译器并没有告诉你,这有一个很好的理由:在大多数实际情况下,它对你来说无论如何都没有任何意义。 从编译器的角度来看,推理线中的所有位都同样重要,但是它们太多了,无法一次打印出来,而且它不知道如何选择对您最有意义的位。
但它确实为您提供了另一条有价值的信息——该位结果有两种不匹配的类型:
同时检查表达式
(apply log) ((append "Quote failed: ") (printError err))
的类型为Aff t0
在这里,我认为编译器可以更好地打印出表达式。 它最终会到达那里,但现在它只需要最小的努力就可以打印出来。 但不要害怕。 我们仍然可以解码它。
看到那边apply
了吗? 那是什么? 你没有把它写在你的代码中,那么它是从哪里来的呢?
好吧,您确实在代码中写了它:美元运算符$
是apply
的别名( 请参阅文档)。 同样,运算符<>
是append
的别名。
知道了这一点,我们就可以将这段代码解码成它的原始形式:
(apply log) ((append "Quote failed: ") (printError err))
(($) log) (((<>) "Quote failed: ") (printError err))
($) log ((<>) "Quote failed: " (printError err))
log $ ("Quote failed: " <> (printError err))
log $ "Quote failed: " <> printError err
你看! 这是您在第 25 行写的位!
好的,那么到目前为止我们知道什么? 我们知道编译器已经确定log $...
表达式一方面必须具有Effect Unit
类型,另一方面必须具有Aff t0
类型。
让我们看看这段代码是什么。 看:这是从Effect.Console
调用log
function( 参见文档)。 它的返回类型是Effect Unit
。 啊哈! 所以这就是编译器认为类型应该是Effect Unit
的原因! 因为它是调用log
函数的结果!
好的,很好,但是Aff t0
呢? 好吧,让我们看看该表达式的结果最终会去哪里:作为launchAff_
的参数( 请参阅文档)。 launchAff_
采用什么类型的参数? 惊喜 - 这是Aff a
!
所以你 go,谜团解决了: launchAff_
需要一个Aff a
类型的参数,但你给它一个Effect Unit
类型的值。 难怪编译器会抱怨!
至于怎么修。
第一个愚蠢的方法是拨打 go 并搜索 Pursuit。 我们有一个Effect Unit
类型的值,我们需要将其转换为Aff a
。 那可能吗? 好吧,让我们 搜索Effect Unit -> Aff a
类型的 function 。 看哪:有这样一个 function,它叫做liftEffect
。 所以我们可以使用它:
Left err -> liftEffect $ log $ "Quote failed: " <> AX.printError err
繁荣。 完毕。
但是,如果是我,我通常会这样想:我不可能是第一个发生这种情况的人。 想要从Aff
上下文中打印到控制台不是很正常吗? 不应该已经有一个应用程序吗?
所以我可能会 go 并搜索合适的类型,例如String -> Aff Unit
。 看看:实际上有一个log
function 适合。 它做同样的事情,但它不像你正在使用的那样专门在Effect
中工作,而是在任何具有MonadEffect
实例的 monad 中工作。 Aff
是这样的单子吗? 好吧,让我们搜索Aff
并查看:是的,是的。 它确实有一个MonadEffect
实例。
所以现在,知道了所有这些,我可能只是将导入从Effect.Console (log)
更改为Effect.Class.Console (log)
,然后我不需要进行任何其他更改:新log
function 将只是在Aff
工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.