简体   繁体   English

您如何理解 Purescript 中的错误消息?

[英]How do you understand error messages in Purescript?

I'm working on building a crypto arbitrage bot in Purescript, mostly to learn about the functional programming paradigm.我正在使用 Purescript 构建一个加密货币套利机器人,主要是为了了解函数式编程范例。 As a JS programmer primarily, I find Purescript's error messages very difficult to interpret.作为主要的 JS 程序员,我发现 Purescript 的错误消息很难解释。 Currently, while trying to use the Affjax library to make an http request I'm running into a 'TypesDoNotUnify' error.目前,在尝试使用 Affjax 库发出 http 请求时,我遇到了“TypesDoNotUnify”错误。 My code looks like this:我的代码如下所示:

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 highlights the line beginning with Left err -> log as the source of the problem, and when I hover over that the error I get the following additional info: VsCode 突出显示以Left err -> log开头的行作为问题的根源,当我 hover 超过该错误时,我得到以下附加信息:

printError:: Error → String Could not match type printError:: 错误 → 字符串无法匹配类型

Effect影响

with type与类型

Aff阿夫

while trying to match type Effect Unit with type Aff t0 while checking that expression (apply log) ((append "Quote failed: ") (printError err)) has type Aff t0 in value declaration sendQuoteRequest在尝试将类型 Effect Unit 与类型 Aff t0 匹配时同时检查表达式(应用日志)((附加“Quote failed:”)(printError err))在值声明 sendQuoteRequest 中具有类型 Aff t0

where t0 is an unknown type PureScript(TypesDoNotUnify)其中 t0 是未知类型 PureScript(TypesDoNotUnify)

What I'm hoping to understand is not only how to fix this error, but to learn a little more about how to interpret the errors that Purescript gives me.我希望了解的不仅是如何修复这个错误,而是更多地了解如何解释 Purescript 给我的错误。 What steps would you take to work through this error if it came up in your code?如果您的代码中出现此错误,您将采取什么步骤来解决它?

The first words in the error message are:错误消息中的第一句话是:

Could not match type Effect with type Aff无法将类型Effect与类型Aff匹配

And then it clarifies a bit:然后它澄清了一点:

while trying to match type Effect Unit with type Aff t0在尝试将类型Effect Unit与类型Aff t0匹配时

This is how the vast majority of type errors will look.这就是绝大多数类型错误的样子。 It means the compiler was following your program along, figuring out which bits have which types, and finally found a bit which from one line of reasoning turned out to have type Effect Unit , but from another line of reasoning turned out to have type Aff t0 (for some as of yet unknown type t0 ).这意味着编译器一直在跟踪您的程序,找出哪些位具有哪些类型,并最终找到一个位,从一行推理中得出的类型为Effect Unit ,但从另一行推理中得出的类型为Aff t0 (对于一些未知的类型t0 )。 Both lines of reasoning are correct, but their results don't match, so the compiler doesn't know what to do next.两行推理都是正确的,但它们的结果不匹配,因此编译器不知道下一步该做什么。

Which were those lines of reasoning you ask?你问的那些推理是什么? Well, the compiler isn't telling you, and there is a good-ish reason for that: in most real cases it wouldn't make any sense to you anyway.好吧,编译器并没有告诉你,这有一个很好的理由:在大多数实际情况下,它对你来说无论如何都没有任何意义。 From the compiler's point of view all bits in the line of reasoning are equally important, but there are too many of them to print all at once, and it doesn't know how to pick the ones that would make most sense to you.从编译器的角度来看,推理线中的所有位都同样重要,但是它们太多了,无法一次打印出来,而且它不知道如何选择对您最有意义的位。

But it does give you another valuable piece of information - which bit turned out to have two mismatching types:但它确实为您提供了另一条有价值的信息——该位结果有两种不匹配的类型:

while checking that expression (apply log) ((append "Quote failed: ") (printError err)) has type Aff t0同时检查表达式(apply log) ((append "Quote failed: ") (printError err))的类型为Aff t0

Here I think the compiler could do a bit of a better job of printing out the expression.在这里,我认为编译器可以更好地打印出表达式。 It will get there eventually, but for now it just prints with minimal effort.它最终会到达那里,但现在它只需要最小的努力就可以打印出来。 But no fear.但不要害怕。 We can still decode it.我们仍然可以解码它。

See that apply over there?看到那边apply了吗? What's that?那是什么? You didn't write that in your code, so where did it come from?你没有把它写在你的代码中,那么它是从哪里来的呢?

Well, you kinda did write it in your code: the dollar operator $ is an alias for apply ( see docs ).好吧,您确实在代码中写了它:美元运算符$apply的别名( 请参阅文档)。 And similarly, the operator <> is an alias for append .同样,运算符<>append的别名。

Knowing that, we can decode this bit of code into its original form:知道了这一点,我们就可以将这段代码解码成它的原始形式:

(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

Hey, look!你看! This is the bit you wrote on line 25!这是您在第 25 行写的位!

Ok, so what do we know so far?好的,那么到目前为止我们知道什么? We know that the compiler has determined that the log $... expression must have the type Effect Unit on one hand and the type Aff t0 on the other hand.我们知道编译器已经确定log $...表达式一方面必须具有Effect Unit类型另一方面必须具有Aff t0类型。

Let's see what this bit of code is.让我们看看这段代码是什么。 Look: it's a call to the log function from Effect.Console ( see docs ).看:这是从Effect.Console调用log function( 参见文档)。 Its return type is Effect Unit .它的返回类型是Effect Unit Aha!啊哈! So that's why the compiler thinks the type should be Effect Unit !所以就是编译器认为类型应该是Effect Unit的原因! Because it's the result of a call to the log function!因为它是调用log函数的结果!

Ok, good, but what about Aff t0 ?好的,很好,但是Aff t0呢? Well, let's see where the result of that expression is ultimately going: as a parameter to launchAff_ ( see docs ).好吧,让我们看看该表达式的结果最终会去哪里:作为launchAff_的参数( 请参阅文档)。 And what type of parameter does launchAff_ take? launchAff_采用什么类型的参数? Surprise - it's Aff a !惊喜 - 这是Aff a

So there you go, mystery solved: launchAff_ expects a parameter of type Aff a , but you're giving it a value of type Effect Unit .所以你 go,谜团解决了: launchAff_需要一个Aff a类型的参数,但你给它一个Effect Unit类型的值。 No wonder the compiler complains!难怪编译器会抱怨!


As for how to fix it.至于怎么修。

The first dumb way to do it is to just go and search on Pursuit.第一个愚蠢的方法是拨打 go 并搜索 Pursuit。 We have a value of type Effect Unit , and we need to convert it to Aff a .我们有一个Effect Unit类型的值,我们需要将其转换为Aff a Is that possible?那可能吗? Well, let's search for a function of type Effect Unit -> Aff a .好吧,让我们 搜索Effect Unit -> Aff a类型的 function And behold: there is such function, it's called liftEffect .看哪:有这样一个 function,它叫做liftEffect So we can just use that:所以我们可以使用它:

    Left err -> liftEffect $ log $ "Quote failed: " <> AX.printError err 

Boom.繁荣。 Done.完毕。

But then, if it was me, I would normally think this way: I can't be the first person this happened to.但是,如果是我,我通常会这样想:我不可能是第一个发生这种情况的人。 Shouldn't it be a normal occurrence to want to print to console from within an Aff context?想要从Aff上下文中打印到控制台不是很正常吗? Should't there be already an app for that?不应该已经有一个应用程序吗?

So I might go and search for a suitable type, for example String -> Aff Unit .所以我可能会 go 并搜索合适的类型,例如String -> Aff Unit And look: there is actually a log function that fits .看看:实际上有一个log function 适合 It does the same thing, but it works not specifically in Effect , like the one you're using, but in any monad that has a MonadEffect instance.它做同样的事情,但它不像你正在使用的那样专门在Effect中工作,而是在任何具有MonadEffect实例的 monad 中工作。 Is Aff such a monad? Aff是这样的单子吗? Well, let's search for Aff and look : yes, it is.好吧,让我们搜索Aff查看:是的,是的。 It does have an instance of MonadEffect .它确实有一个MonadEffect实例。

So now, knowing all of that, I might just change my import from Effect.Console (log) to Effect.Class.Console (log) , and then I don't need to make any other changes: the new log function will just work in Aff .所以现在,知道了所有这些,我可能只是将导入从Effect.Console (log)更改为Effect.Class.Console (log) ,然后我不需要进行任何其他更改:新log function 将只是在Aff工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM