Java 8有一个内置的JavaScript引擎,名为Nashorn,因此实际上可以在JVM上运行编译为JavaScript的Haskell。
以下程序有效:
{-# LANGUAGE JavaScriptFFI #-}
module Main where
foreign import javascript unsafe "console={log: function(s) { java.lang.System.out.print(s); }}"
setupConsole :: IO ()
foreign import javascript unsafe "java.lang.System.exit($1)"
sysexit :: Int -> IO ()
main = do
setupConsole
putStrLn "Hello from Haskell!"
sysexit 0
我们可以运行它:( 旁注:可以将它作为普通的Java程序运行。jjs
只是在JVM上运行纯JavaScript代码的便捷方式)
$ ghcjs -o Main Main.hs
[1 of 1] Compiling Main ( Main.hs, Main.js_o )
Linking Main.jsexe (Main)
$ which jjs
~/bin/jdk/bin/jjs
$ jjs Main.jsexe/all.js
Hello from Haskell!
在上面的代码中,console.log
需要使用java.lang.System.print
定义,因为Nashorn不提供默认的全局console
对象和Haskell的putStrLn
否则似乎没有打印任何东西。
另一个原因是JVM需要退出sysexit
用java.lang.System.exit
实现的FFI功能。
我有两个问题:
console.log
类似,在必须定义的ghcjs中假设了哪些其他主机依赖?答案 0 :(得分:2)
在luite的帮助下,我终于得到了shims for the JVM的一点点工作:
Java的Nashorn提供全局Java
变量,可用于检测我们是否在JVM下运行。如果定义了此变量,则为ghcjs运行时设置类似于h$isJvm
的全局变量h$isNode
。然后,此变量将用于在其他位置提供JVM特定代码。我们也可以在这里定义console.log
,这样写入控制台就可以在JVM上开箱即用,而无需在用户程序中定义它:
if(typeof Java !== 'undefined') {
h$isJvm = true;
this.console = {
log: function(s) {
java.lang.System.out.print(s);
}
};
}
GHCJS有一个名为h$exitProcess
的方法,用于退出流程。使用我们在上一步h$isJvm
中定义的变量,我们可以为JVM添加以下代码以退出:
if (h$isJvm) {
java.lang.System.exit(code);
}
Nashorn提供了一个全局arguments
变量,其中包含传递给jjs
的命令行参数值。我们可以使用这个变量添加垫片:
if(h$isJvm) {
h$programArgs = h$getGlobal(this).arguments;
}
使用这些填充程序,我们可以在JVM上运行大多数Haskell。这是问题中的原始程序,GHCJS中添加了上述填充程序:
module Main where
main = putStrLn "Hello from Haskell!"
这个常规的Haskell代码现在可以在JVM中运行。即使是非常重要的小部分也直接在JVM上运行。例如,以下代码取自here:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
import Options.Generic
data Example = Example { foo :: Int, bar :: Double }
deriving (Generic, Show)
instance ParseRecord Example
main = do
x <- getRecord "Test program"
print (x :: Example)
我们可以使用stack
构建它并使用jjs
运行命令行参数:
haskell-jvm-hello$ stack build
haskell-jvm-hello$ jjs ./.stack-work/dist/x86_64-linux/Cabal-1.22.4.0_ghcjs/build/haskell-jvm-hello-exe/haskell-jvm-hello-exe.jsexe/all.js -- --help
Test program
Usage: a.js --foo INT --bar DOUBLE
Available options:
-h,--help Show this help text
haskell-jvm-hello$ jjs ./.stack-work/dist/x86_64-linux/Cabal-1.22.4.0_ghcjs/build/haskell-jvm-hello-exe/haskell-jvm-hello-exe.jsexe/all.js -- --foo 1 --bar 2.5
Example {foo = 1, bar = 2.5}
答案 1 :(得分:0)
仅供记录,这也是github
的问题那里的答案指向existing平台检测代码,以及流程退出functionality。这些和相关领域将提供ghcjs可以扩展的点,以支持jvm作为特定平台。