我正在尝试用下面的 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
。
如果有人能让我知道我还做错了什么,我将不胜感激。
我怀疑这是由于
>>=
Lwt 中的类型是在左侧,您将 的结果传递给它
Client.get url
,因此右侧必须是返回相同类型的函数。同样,Lwt.run
期望Lwt.t
。(我并不熟悉所涉及的所有库,但Client.io
可能是类型同义词扩展到Lwt.t
此处。)此示例的修复方法是使用
>|=
而不是第二个>>=
,其类型为Andreas Rossberg 已经发现了一个问题,但您还看到一些运算符优先级问题。
这种事:
还有这个:
看起来真的很可疑,因为无法将
printf "HTTP code: "
的求值()
提供给^
。看起来你想要写类似这样的内容:但是您不妨利用
printf
下面的方法编写,它更干净并且没有运算符优先级问题。还要注意打开多个模块。如果多个模块定义了相同的运算符,或者它们重新定义了标准库运算符,则可能会出现一些意外行为。
除了完全限定名称外,您还可以本地打开模块,从而缓解此问题。但由于您已经在代码中使用过一次,因此您似乎知道此选项。
从风格上看,我可能只会重构这一点:
到:
也有意见,但有机会重新修改:
使用模式匹配和条件保护: