【问题标题】:How can I call an individual Idris function from JavaScript?如何从 JavaScript 调用单个 Idris 函数?
【发布时间】:2019-07-19 22:44:51
【问题描述】:

假设我在 Idris 中有一个函数可以进行一些计算。为简单起见,暂时将其 stringly 输入。

f: String -> String

如何将此函数编译为 JavaScript,以便可以从任何普通 JavaScript 代码调用它?

如果这太简单了,假设 f 处理 String 而不是 Double 甚至是自定义 Idris 数据类型。

我知道我可以使用Main.main 函数编译整个模块,并且将输出或多或少难以理解的 JavaScript blob。我可以从那里手动提取我的功能吗?我该怎么办?


P.S.尽管我自己回答,但我仍在寻找更好的解决方案,所以欢迎。

【问题讨论】:

    标签: javascript ffi idris


    【解决方案1】:

    使用this example,至少使用Node 后端似乎是可行的。我已将interact 标记为export 并添加了library 描述符:

    module Main
    
    import Data.String
    
    f: Double -> Double
    f x = x + 1
    
    export interact: String -> String
    interact s = let x = parseDouble s in
        case x of
             Nothing => "NaN"
             Just x => show (f x)
    
    main: IO ()
    main = do
        s <- getLine
        putStrLn (interact s)
    
    lib : FFI_Export FFI_JS "" []
    lib = Data String "String" $
          Fun interact "interact" $
          Fun main "main" $
          End
    

    然后我使用--interface 标志进行编译(使用--codegen javascript...失败):

    idris --codegen node --interface  --output ExportToJS.js ExportToJS.idr
    

    生成的.js 文件末尾有这个:

    module.exports = {
    interact: Main__interact,
    main: Main__interact
    };
    }.call(this))
    

    这应该允许您从 Node 中执行 require("./ExportToJavaScript.js").interact("42"),并且可能有一个等效于从浏览器中使用的方法。

    【讨论】:

      【解决方案2】:

      是的,您可以手动提取任何功能。

      1. 如下构建模块:

        module Main
        
        import Data.String
        
        f: Double -> Double
        f x = x + 1
        
        interact: String -> String
        interact s = let x = parseDouble s in
            case x of
                 Nothing => "NaN"
                 Just x => show (f x)
        
        main: IO ()
        main = do
            s <- getLine
            putStrLn (interact s)
        
      2. 编译如下:

        % idris --codegen javascript --output Main.js Main.idr
        

        将创建一个名为Main.js 的文件。正如你所说,会有几兆字节或多或少难以理解的 JavaScript 代码。

      3. 手动编辑此文件,并与此类似:

        --- Resistors.js
        +++ Resistors-default.js
        @@ -1,7 +1,5 @@
         "use strict";
        
        -(function(){
        -
         const $JSRTS = {
             throw: function (x) {
                 throw x;
        @@ -36130,7 +36128,3 @@
                 }
             }
         }
        -
        -
        -$_0_runMain();
        -}.call(this))
        
      4. 现在请注意,这个 JS 文件中有 cmets,用它们的 Idris 名称标记 JS 函数。比如对应我们的interact函数就会有这个JS函数:

        // Main.interact
        
        function Main__interact($_0_arg){
            const $_1_in = Data__String__parseDouble($_0_arg);
        
            if(($_1_in.type === 1)) {
                const $cg$3 = Main__bestMatch_39_($_1_in.$1, Main__manyResistors_39_());
                let $cg$2 = null;
                $cg$2 = $cg$3.$1;
                return Prelude__Show__Main___64_Prelude__Show__Show_36_Schema_58__33_show_58_0($cg$2);
            } else {
                return "NaN";
            }
        }
        
      5. 如果您将此 JS 文件作为脚本附加到网页,则可以在浏览器中打开 JS 控制台并与您的 Idris 函数进行交互,如下所示:

        Main__interact("10")
        "11"
        

      希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-07
        • 2018-08-15
        • 2012-07-04
        • 2014-03-23
        相关资源
        最近更新 更多