Ocaml Lwt_流的使用和设计问题
我正在编写一个基于lwt的TwitterAPI库,我想使用lwt_流库实现TwitterAPI的功能 我决定使用Ocaml Lwt_流的使用和设计问题,ocaml,Ocaml,我正在编写一个基于lwt的TwitterAPI库,我想使用lwt_流库实现TwitterAPI的功能 我决定使用Lwt\u stream.from并为该函数提供一个参数f 以下是我目前的工作 let get_follower ~access_token ~screen_name ?(count=5000) ?(wait=true) () = let base_uri = "https://api.twitter.com/1.1/followers/ids.json" in let cur
Lwt\u stream.from
并为该函数提供一个参数f
以下是我目前的工作
let get_follower ~access_token ~screen_name ?(count=5000) ?(wait=true) () =
let base_uri = "https://api.twitter.com/1.1/followers/ids.json" in
let cursor = ref (-1) in
let f () =
Client.do_get_request
~uri_parameters:
["screen_name", screen_name;
"cursor", (string_of_int (!cursor));
"count", (string_of_int count)]
~uri:(Uri.of_string base_uri)
~access_token:access_token
() >>= fun res ->
match res with
| Ok (header, str) -> begin
match (Yojson.Safe.from_string str |> user_ids_of_yojson) with
| `Ok uids ->
cursor := uids.next_cursor;
return (Some (Ok uids))
| `Error msg -> failwith msg
end
| Error e -> return (Some (Error (process_error_exn e))) in
Lwt_stream.from f
我不确定是否应该使用ref
我使用ref
的原因是f
的行为取决于它之前返回的值。具体来说,下次将使用的光标的值取决于当前下一个光标
,如果光标
为零,f
知道它到达末尾并返回None
在这里使用ref
被认为是一个好的设计选择吗?有没有更好的方法来实现此功能 因为f
需要单位
并且每次都会产生不同的结果,正如你所说的,它必须依赖于某种状态,正如我想你已经意识到的那样。它已经通过依赖I/O的结果实现了这一点,我认为这就是为什么ref
的问题不容易回答的原因。否则,答案将是肯定的,这是必要的(见下文第(2)点)
我认为有两种主要的可能性可以消除语法上的ref
,但它们都没有意义
以某种方式将这些状态位隐藏在I/Of
已经在做的事情中,即在API的对等方上。这似乎是不可能的,事实上,看起来这些位必须位于客户端,API才能正常工作
将这些状态位隐藏在客户端的其他位置。但是在某种程度上,在客户机的某个地方仍然会有精神上等同于ref
的东西。您可以编写或使用某种包装器来分析这个ref
,但是除非这个包装器在很多地方都有用,否则它只会使这里存在额外的客户端状态变得不那么明显。我更愿意让州保持地方性,尽可能接近它的用途。既然f
已经不可避免地做了“肮脏”的事情,f
是正确的地方
总之,我要说保持ref
的原样。不管怎样,流都是有状态的
以上讨论假设您必须使用Lwt\u流
。如果没有,您可以提供一个替代接口,其类型类似于get\u follower:cursor:int->…->(results*cursor)Lwt.t
,并让调用者在必要时担心状态。这可能是我首先要尝试的
编辑
当然,这样做有一个缺点,那就是可能会编写调用代码来提供错误的游标。您可以通过返回部分应用的函数来隐藏光标,但是调用代码可能是为了调用错误的函数而编写的。没有线性类型,如果您担心这些可能性,流方法更安全,因此它有它的优势。因为f
采用单位
,并且每次产生不同的结果,正如您所说,它必须依赖于某些状态,我想您已经意识到。它已经通过依赖I/O的结果实现了这一点,我认为这就是为什么ref
的问题不容易回答的原因。否则,答案将是肯定的,这是必要的(见下文第(2)点)
我认为有两种主要的可能性可以消除语法上的ref
,但它们都没有意义
以某种方式将这些状态位隐藏在I/Of
已经在做的事情中,即在API的对等方上。这似乎是不可能的,事实上,看起来这些位必须位于客户端,API才能正常工作
将这些状态位隐藏在客户端的其他位置。但是在某种程度上,在客户机的某个地方仍然会有精神上等同于ref
的东西。您可以编写或使用某种包装器来分析这个ref
,但是除非这个包装器在很多地方都有用,否则它只会使这里存在额外的客户端状态变得不那么明显。我更愿意让州保持地方性,尽可能接近它的用途。既然f
已经不可避免地做了“肮脏”的事情,f
是正确的地方
总之,我要说保持ref
的原样。不管怎样,流都是有状态的
以上讨论假设您必须使用Lwt\u流
。如果没有,您可以提供一个替代接口,其类型类似于get\u follower:cursor:int->…->(results*cursor)Lwt.t
,并让调用者在必要时担心状态。这可能是我首先要尝试的
编辑
当然,这样做有一个缺点,那就是可能会编写调用代码来提供错误的游标。您可以通过返回部分应用的函数来隐藏光标,但是调用代码可能是为了调用错误的函数而编写的。没有线性类型,如果您担心这些可能性,流方法更安全,因此它有它的优势。因为f
采用单位
,并且每次产生不同的结果,正如您所说,它必须依赖于某些状态,我想您已经意识到。它已经通过依赖I/O的结果实现了这一点,我认为这就是为什么ref
的问题不容易回答的原因。否则,答案将是肯定的,这是必要的(见下文第(2)点)
我认为有两种主要的可能性可以消除语法上的ref
,但它们都没有意义
以某种方式将这些状态位隐藏在I/Of
已经在做的事情中,即在API的对等方上。这似乎是不可能的,事实上,看起来A的位必须在客户机上
let get_follower ~access_token ~screen_name ?(count=5000) ?(wait=true) () =
let base_uri = "https://api.twitter.com/1.1/followers/ids.json" in
let make_request cursor =
Client.do_get_request
~uri:(Uri.of_string base_uri) ~access_token
~uri_parameters:[
"screen_name", screen_name;
"cursor", string_of_int cursor;
"count", string_of_int count
] () in
let parse_response = function
| Error e -> Error (process_error_exn e)
| Ok (header, str) ->
match Yojson.Safe.from_string str |> user_ids_of_yojson with
| `Ok uids -> Ok uids
| `Error msg -> failwith msg in
let stream,push = Lwt_stream.create () in
let rec loop cursor =
make_request cursor >|= parse_response >>= function
| Ok {next_cursor=0} -> push None; return_unit
| Ok {next_cursor=n} as r -> push (Some r); loop n
| error -> push (Some error); loop cursor in
async (fun () -> loop (-1));
stream
module Follower : sig
type t
val name : t -> string Lwt.t
...
end