高阶函数的可选参数

Optional arguments for higher-order functions

我尝试为 socket.io 编写绑定。

我在使用函数(底部示例代码中的 next())时遇到问题,该函数不带参数或错误对象 (Js.Exn.raiseError("ERROR!"))。

我找不到一种方法来定义可以将两种类型的参数作为第一个值的函数签名。

我什至不确定,如果我所要求的内容可以在重写中实现,如果能以正确的重写方式帮助解决该问题,我们将不胜感激。

我当前的实现如下所示:

type server
type socket
type next = (. unit) => unit 

@new @module("socket.io") external socketIO: unit => server = "Server"
@send external use: (server, (socket, next) => unit) => unit = "use"
@send external listen: (server, int) => unit = "listen"
@send external on: (server, @string [ #connection(socket => unit) ] ) => unit = "on"

let io = socketIO()

io->use((socket, next) => {
    Js.log("FIRST")
    next(.)
})

io->use((socket, next) => {
    Js.log("SECOND")
    next(.)
})

io->on(#connection(socket => 
    Js.log("CONNECT")
))

io->listen(3000)

通常不可能有一个参数数量可变的函数,但可以传递 undefined 或一个值,这在大多数情况下是等效的。

一种方法是简单地使用 option 类型。如果我们重新定义 next

type next = (. option<int>) => unit 

我们可以这样使用

io->use((_socket, next) => {
    next(. None)
    next(. Some(42))
})

这将生成以下 JavaScript:

io.use(function (_socket, next) {
      next(undefined);
      return next(42);
    });

另一个选项可能是使用可选参数,但这似乎不适用于 uncurrying,最近出现了 currying 的错误,编译器作者似乎没有兴趣修复,所以它可能在那里不起作用要么,但它可能值得一试:

type next = (~error: int=?, unit) => unit
...
io->use((_socket, next) => {
    next(())
    next(~error=42, ())
})

最后,socket.io (bs-socket.io) 已经存在一些绑定。不幸的是,这些也不能处理这种情况,但至少可以使您免于重新发明一些轮子。