代码之家  ›  专栏  ›  技术社区  ›  Vlam

此表达式的类型为unit,但表达式的类型应为'a Client.io

  •  0
  • Vlam  · 技术社区  · 8 月前

    我试图在下面用OCaml编写一个简单的可执行代码。

    open Printf
    open Lwt
    open Cohttp
    open Cohttp_lwt_unix
    open Yojson
    
    let () =
      let ip = "8.8.8.8" in
      let key = "" in
      let uri =
        Uri.of_string
          ("https://api.ip2location.io/?format=json&key=" ^ key ^ "&ip=" ^ ip)
      in
      Lwt_main.run
        ( Client.get uri >>= fun (resp, body) ->
          let code = resp |> Response.status |> Code.code_of_status in
          let json_promise = body |> Cohttp_lwt.Body.to_string in
          json_promise >>= fun json_string ->
          let json = Basic.from_string json_string in
          let open Yojson.Basic.Util in
          if code == 200 then
            if member "usage_type" json <> `Null then
              let usage_type = json |> member "usage_type" |> to_string in
              printf "usage_type: %s\n" usage_type
            else
              printf
                "ERROR: The usage_type field requires a paid subscription to the \
                 Starter plan or higher."
          else if (code == 400 || code == 401) && member "error" json <> `Null then
            let error_message =
              json |> member "error" |> member "error_message" |> to_string
            in
            printf "ERROR: " ^ error_message
          else printf "HTTP Code: " ^ Int.to_string code )
    

    但我跑步时总是看到下面 dune build .

    File "bin/main.ml", line 24, characters 10-46:
    24 |           printf "usage_type: %s\n" usage_type
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Error: This expression has type unit but an expression was expected of type
             'a Client.io
    

    从其他StackOverflow帖子来看,这似乎与 if/else 但我已经确保了所有 if/else 正在使用 printf .

    如果有人能告诉我我还做错了什么,我将不胜感激。

    2 回复  |  直到 8 月前
        1
  •  1
  •   Chris    8 月前

    Andreas Rossberg发现了一个问题,但你也看到了一些 operator precedence 问题。

    这类事情:

    printf "ERROR: " ^ error_message
    

    还有这个:

    printf "HTTP Code: " ^ Int.to_string code
    

    看起来很可疑,因为 printf "HTTP code: " 评估为 () 无法提供给 ^ 。看起来你是想写这样的东西:

    printf ("HTTP Code: " ^ Int.to_string code)
    

    但你也可以利用 printf 编写以下内容,它更清晰,没有运算符优先级问题。

    printf "HTTP Code: %d" code
    

    还要小心打开几个模块。如果多个运算符定义了相同的运算符,或者它们重新定义了标准库运算符,则可能会出现一些意外行为。

    除了完全符合条件的名字,你还可以 当地 开放模块,缓解了这个问题。但是,由于您已经在代码中使用过一次,因此您似乎知道这个选项。

    从风格上讲,我可能只是重构了这个:

            let error_message =
              json |> member "error" |> member "error_message" |> to_string
            in
            printf "ERROR: " ^ error_message
    

    致:

            json 
            |> member "error" 
            |> member "error_message" 
            |> to_string
            |> printf "ERROR: %s"
    

    也有意见,但有机会返工:

          if code == 200 then
            if member "usage_type" json <> `Null then
              let usage_type = json |> member "usage_type" |> to_string in
              printf "usage_type: %s\n" usage_type
            else
              printf
                "ERROR: The usage_type field requires a paid subscription to the \
                 Starter plan or higher."
          else if (code == 400 || code == 401) && member "error" json <> > `Null then
            let error_message =
              json |> member "error" |> member "error_message" |> to_string
            in
            printf "ERROR: " ^ error_message
          else printf "HTTP Code: " ^ Int.to_string code )
    

    使用模式匹配和条件保护:

          match code with
          | 200 when member "usage_type" json <> `Null ->
            json
            |> member "usage_type" 
            |> to_string
            |> printf "usage_type: %s\n"
          | 200 ->
            printf
              "ERROR: The usage_type field requires a paid subscription to the \
               Starter plan or higher."
          | (400 | 401) when member "error" json <> `Null ->
            json 
            |> member "error" 
            |> member "error_message" 
            |> to_string
            |> printf "ERROR: %s"
          | _ -> printf "HTTP Code: %d" code
    
        2
  •  1
  •   Andreas Rossberg    8 月前

    我怀疑这是由于 >>= ,其Lwt类型为

    (>>=) : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.t
    

    在左侧,您将传递以下结果 Client.get url ,因此右侧必须是返回相同类型的函数。同样地, Lwt.run 期待A Lwt.t (我对所有涉及的图书馆都不太熟悉,但 Client.io 大概是一个类型同义词扩展到 Lwt。t 这里)

    这个例子的修复应该是使用 >|= 而不是第二个 >>= ,其类型为

    (>|=) : 'a Lwt.t -> ('a -> 'b) -> 'b Lwt.t
    
    推荐文章