在 buckle 脚本中定义一个闭包变量

Define a closure variable in buckle script

我正在尝试将以下 ES6 脚本转换为 bucklescript,但我终生无法弄清楚如何在 bucklescript

中创建 "closure"
    import {Socket, Presence} from "phoenix"

    let socket = new Socket("/socket", {
      params: {user_id: window.location.search.split("=")[1]}
    })

    let channel = socket.channel("room:lobby", {})
    let presence = new Presence(channel)

    function renderOnlineUsers(presence) {
      let response = ""

      presence.list((id, {metas: [first, ...rest]}) => {
        let count = rest.length + 1
        response += `<br>${id} (count: ${count})</br>`
      })

      document.querySelector("main[role=main]").innerHTML = response
    }

    socket.connect()

    presence.onSync(() => renderOnlineUsers(presence))

    channel.join()

我无法具体弄清楚的部分是 let response = ""(或者在这种情况下是 var,因为 bucklescript 总是使用 vars):

    function renderOnlineUsers(presence) {
      let response = ""

      presence.list((id, {metas: [first, ...rest]}) => {
        let count = rest.length + 1
        response += `<br>${id} (count: ${count})</br>`
      })

      document.querySelector("main[role=main]").innerHTML = response
    }

到目前为止我得到的最接近的不包括 result 声明

...
...

let onPresenceSync ev =
  let result = "" in
    let listFunc = [%raw begin
        {|
          (id, {metas: [first, ...rest]}) => {
            let count = rest.length + 1
            result += `${id} (count: ${count})\n`
          }
        |}
      end
    ] in
      let _ =
        presence |. listPresence (listFunc) in
          [%raw {| console.log(result) |} ]
...
...

编译为:

function onPresenceSync(ev) {
  var listFunc = (
          (id, {metas: [first, ...rest]}) => {
            let count = rest.length + 1
            result += `${id} (count: ${count})\n`
          }
        );
  presence.list(listFunc);
  return ( console.log(result) );
}

result 作为优化被删除,因为它被认为未使用。使用依赖于 BuckleScript 生成的代码的 raw 代码通常不是一个好主意,因为在生成的代码中您可能会遇到很多意外。

改变编译器认为不可变的变量也不是一个好主意,因为它会基于值永远不会改变的假设来执行优化。

此处最简单的修复方法是将 [%raw {| console.log(result) |} ] 替换为 Js.log result,但看看 listFunc 如何用 OCaml 编写可能会有所启发:

let onPresenceSync ev =
  let result = ref "" in
  let listFunc = fun [@bs] id item ->
    let count = Js.Array.length item##meta in
    result := {j|$id (count: $count)\n|j}
  in
  let _ = presence |. (listPresence listFunc) in
    Js.log !result

请注意,result 现在是一个 ref 单元格,这是您在 OCaml 中指定可变变量的方式。 ref 单元格使用 := 更新,它包含的值使用 ! 检索。另请注意 [@bs] 注释,用于指定传递给外部高阶函数的函数所需的 an uncurried function。以及使用的字符串插值语法:{j| ... |j}