如何将 PureScript ADT 转换为 FFI 的 JS 字符串 'enum'

How turn a PureScript ADT into JS String 'enum' for FFI

我正在查看 JS 的一些文档,它使用字符串作为权宜之计 'enum'。在我的应用程序中最好将其表示为代数数据类型 ADT;但是,我不太确定将 ADT 转换为对象上的 String 以供外部函数接口 FFI 使用的最佳方法是什么。从概念上给出:

data Foo = Bar | Baz

type Qux = { foo :: Foo }

foreign import quux :: forall e. Qux -> Eff (console :: CONSOLE | e) Unit

main = do
  quux { foo : Bar }

qux{ foo : "bar" | "baz" }

exports.quux = function(qux) {
  return function() { 
    console.log(qux)
    //=> Object { foo : "bar" }
  }
}

在 Elm 中,我会在 core 中使用 Json.Encode 将记录转换为 JS 对象以传递它,但我不确定 PureScript 中的模拟。

我会这样做:

data Foo = Bar | Baz

printFoo :: Foo -> String
printFoo = case _ of
  Bar -> "bar"
  Baz -> "baz"

type Qux = { foo :: Foo }

foreign import _quux :: forall e. { foo :: String } -> Eff (console :: CONSOLE | e) Unit

quux :: forall e. Qux -> Eff (console :: CONSOLE | e) Unit
quux args = _quux { foo: printFoo args.foo }

main = do
  quux { foo : Bar }

想法是将 FFI 函数 _quux 的参数调整为 quux,然后避免从模块中导出 _quux,因此只有 "safe" 接口可以访问。

这种方法的另一个优点是您可以为 quux 函数提供更多 PS-friendly 参数设置,因为将记录作为选项传递通常不是规范,除非该函数将接受一个很多东西:

quux :: forall e. Foo -> Eff (console :: CONSOLE | e) Unit
quux foo = _quux { foo: printFoo foo }

main = do
  quux Bar

基本上我的建议是,无论何时使用 FFI,您都希望在 FFI 中做尽可能少的工作,并在 PS 中处理尽可能多的实现。这样,您编写的更多代码仍可由编译器检查,并且您不必在 JS 中做任何巧妙的事情,也不必编写如果 PS 的实现细节在未来某个版本中发生变化可能会破坏的东西。