PureScript - AFF require(...).main 不是函数

PureScript - AFF require(...).main is not a function

考虑以下代码示例,直接取自手册中关于异步效果的章节。

-- https://book.purescript.org/chapter9.html
module Main where 

import Prelude
import Data.Either (Either(..))
import Effect.Aff (Aff, attempt, message)
import Effect.Class.Console (log)
import Node.Encoding (Encoding(..))
import Node.FS.Aff (readTextFile, writeTextFile)
import Node.Path (FilePath)

copyFile :: FilePath -> FilePath -> Aff Unit
copyFile file1 file2 = do
  my_data <- readTextFile UTF8 file1
  writeTextFile UTF8 file2 my_data

main :: Aff Unit
main = do
  result <- attempt $ copyFile "file1.txt" "file2.txt"
  case result of
    Left e -> log $ "There was a problem with copyFile: " <> message e
    _ -> pure unit

但是,当此应用程序 运行 与 Spago 运行 一起使用时,它会产生以下令人费解的错误,这似乎类似于 JavaScript 错误而不是 PureScript 错误。

require(...).main is not a function

问题如下:

  1. 必须以何种方式更改此代码才能产生所需的效果(文件的复制)
  2. 导致上述错误的原因是什么疏忽或配置错误?

简短回答:main 必须是 Effect,而不是 Aff


你的main是一个Aff,错误信息是绝对正确的:Aff确实不是一个函数。它是一个代表异步计算的 non-trivial 数据结构,它不能从 JavaScript 简单地“启动”而不涉及太多 PureScript 内部结构。

另一方面,

Effect 在 JavaScript 端被建模为无参数函数。例如,像这样:

f :: Effect Int
f = pure 42

像这样编译为 JavaScript:

const f = () => 42

通过示例对这一事实进行了更长的讨论。

所以,如果你给你的 main 类型 Effect Unit,就可以从 JavaScript 像这样简单地调用它:

require("output/Main/index.js").main()

只是调用一个没有参数的函数。这正是运行时试图做的。


但是如果您需要在 main 中执行异步操作怎么办?

您可以通过 launchAff_ 启动 Aff 异步计算,它本身具有类型 Effect Unit,但将 Aff 计算作为参数并异步启动它:

main :: Effect Unit
main = launchAff_ do
  result <- attempt $ copyFile "file1.txt" "file2.txt"
  case result of
    Left e -> log $ "There was a problem with copyFile: " <> message e
    _ -> pure unit

这样,main 函数本身将调用 launchAff_ 并立即终止,但启动的 Aff 计算将继续,程序不会退出,直到最后一个 Aff计算停止。