如何从 java evaluate/run frege IO () monad?

How to evaluate/run frege IO () monad from java?

首先对我的英语感到抱歉,而且我正在努力学习 Haskell

我会 运行 从 java 调用 Frege 代码 (Haskell),几乎所有 我设法按照找到的说明使其全部工作 在各种网站上......但我仍然对以下代码有疑问, 对请求的冗长感到抱歉...

javaHelloTest.java

package local.java;

import java.io.PrintWriter;
import java.util.Arrays;

import frege.runtime.Runtime;
import frege.runtime.Runtime.*;
import frege.java.Util.TList;
import frege.prelude.PreludeArrays;
import frege.prelude.PreludeBase;
import frege.control.monad.State;
import frege.run7.*;
import local.frege.FregeHelloTest;

public class JavaHelloTest {
        public static void main(String[] args) {
                System.out.println("Hello World from Java code ... ");
                System.out.println("========================");
                System.out.println("callingMain0 ... ");
                System.out.println("------------------------");
                FregeHelloTest.callingMain0(Thunk.<PreludeBase.TList<String>>lazy(PreludeArrays.IListSource_JArray.<String>toList(args)));
                System.out.println("========================");
                System.out.println("callingMain1 ... ");
                System.out.println("------------------------");
                FregeHelloTest.callingMain1(Thunk.   <PreludeBase.TList<String>>lazy(PreludeArrays.IListSource_JArray.<String>toList(args)));
                System.out.println("========================");
                System.out.println("callingMain2 ... ");
                System.out.println("------------------------");
                FregeHelloTest.callingMain2(Thunk.   <PreludeBase.TList<String>>lazy(PreludeArrays.IListSource_JArray.<String>toList(args)));
                System.out.println("========================");
        }
}

fregeHelloTest.fr

module local.frege.FregeHelloTest where

import Prelude.PreludeBase as PreludeBase

main :: [String] -> IO ()
main args = println $ "Hello World from Frege code ..."

callingMain0 :: [String] -> ()
callingMain0 ss = PreludeBase.ST.performUnsafe(main ss) 

callingMain1 :: [String] -> IO ()
callingMain1 ss = return ( PreludeBase.ST.performUnsafe(main ss) )

callingMain2 :: [String] -> ()
callingMain2 ss = PreludeBase.ST.run( return ( PreludeBase.ST.performUnsafe(main ss) ) )

fregeHelloTest.java(从 fregec 生成)

{ ... omissis ... }

final public class FregeHelloTest  {

final public static Func.U<RealWorld, Short> $main(final Lazy<PreludeBase.TList<String/*<Character>*/>> arg) {
return PreludeBase.<Func.U<RealWorld, Short>, String/*<Character>*/>$(
               new Func.U.D<String/*<Character>*/, Func.U<RealWorld, Short>>() {
                 public Lazy<Func.U<RealWorld, Short>> apply(final Lazy<String/*<Character>*/> η11) {
                   return Thunk.<Func.U<RealWorld, Short>>shared(
                             new Lazy.D<Func.U<RealWorld, Short>>() {
                               public Func.U<RealWorld, Short> call() {
                                 return Prelude.<String/*<Character>*/>println(PreludeText.IShow_String.it, η11.call());
                               }
                             }
                           );
                 }
               },
               Thunk.<String/*<Character>*/>lazy("Hello World from Frege code ...")
             ).call();
   }

final public static short callingMain2(final Lazy<PreludeBase.TList<String/*<Character>*/>> arg) {
  return (short)PreludeBase.TST.<Short>run(
            PreludeMonad.IMonad_ST.<Object, Short>pure(
                  Thunk.<Short>nested(
                        new Lazy.D<Lazy<Short>>() {
                          public Lazy<Short> call() {
                            return PreludeBase.TST.<Short>performUnsafe(FregeHelloTest.$main(arg));
                          }
                        }
                      )
                )
          ).call();
}

final public static Func.U<RealWorld, Short> callingMain1(final Lazy<PreludeBase.TList<String/*<Character>*/>> arg) {
  return PreludeMonad.IMonad_ST.<RealWorld, Short>pure(
            Thunk.<Short>nested(
                  new Lazy.D<Lazy<Short>>() {
                    public Lazy<Short> call() {
                      return PreludeBase.TST.<Short>performUnsafe(FregeHelloTest.$main(arg));
                    }
                  }
                )
          );
}

final public static short callingMain0(final Lazy<PreludeBase.TList<String/*<Character>*/>> arg) {
  return (short)PreludeBase.TST.<Short>performUnsafe(FregeHelloTest.$main(arg)).call();
}

public static void main(final java.lang.String[] argv) { ... omissis ... }

}

程序输出...入口点:local.java.JavaHelloTtest.main

------------------
Hello World from Java code ... 
========================
callingMain0 ... 
------------------------
Hello World from Frege code ...
========================
callingMain1 ... 
------------------------
========================
callingMain2 ... 
------------------------
Hello World from Frege code ...
========================

经过长时间的(对我而言)调查,我意识到这是正确的 "CallingMain1" 不执行任何操作...事实上,如您所见 由 "callingMain2" 生成需要 "run" ... 但如果我尝试 使用 "run" 执行,返回 "callingMain1" IDE (Eclipse 然后是编译器)告诉我签名不正确, PreludeBase.TST.运行 在 "Object" 而不是 "RealWorld", 事实上,编译器在 "callingMain2" 的情况下设置了一个 "Object" 而不是 "RealWorld" 到 运行 callingMain2.

显然(我认为)"callingMain1" 的签名(Haskell)是正确的... 而且我认为没有人可以触摸...

现在的问题......在这一点上我认为,也许应该是 一个功能... TST.runOnRealWorld 允许评估 IO() 还从"callingMain1" 返回;然而,就像这一代人一样 of "callingMain2" 我清楚地看到操作被改变了 即时 "Object" 我不得不假设这个函数不存在...

这是想要的或者只需要添加一个"run"方法 允许 java 评估 "callingMain1" ?

的输出

或者,更有可能的是,我了解得很少......提前致谢......

首先,我想说没有必要为努力学习而感到遗憾Haskell。从相反的方面来说。认为自己属于精英,insead!

callingMain0 生成的 java 代码是 运行 来自 Java 的 I/O 操作的正确代码。我建议直接使用它(或通过 Java 实用方法),出于卫生原因,不要像 callingMain0 这样看似纯粹的辅助函数。

顺便说一句,当你传递一个具有 Frege 代数数据类型的值(枚举除外)时,你不需要将它包装在额外的 Thunk.<...>lazy() 中,因为所有这些类型都已经实现了 Lazy界面。所以你可以这样写:

FregeHelloTest.callingMain0(PreludeArrays.IListSource_JArray.<String>toList(args));

无论函数实际需要惰性列表还是严格列表,这都有效。

接下来,callingMain1 当然,它什么都不做,就像

FregeHelloTest.$main(...) 

什么都不做。为什么?因为类型是 IO () 这种类型告诉我们函数 returns 一个动作,当该动作被执行时将产生一个 () 。而在 Frege 中 only 执行 IO 动作的方式是通过 PreludeBase.TST.<T>performUnsafe。但是您没有将操作(即调用 callingMain1(...) 的结果)传递给 performUnsafe。因此,该操作永远不会执行。

备注:当您检查为您的 Frege 模块生成的代码时,您可能已经注意到 main 方法的存在。如果没有,请查找。您会看到 JVM 输入的 main 方法只是通过将其结果传递给 performUnsafe 来调用 $main(对应于您的 Frege main 函数)。没有别的办法了。

还有一个说法:有一个广为流传的误解,即 Haskell(或 Frege)类型为 IO 的函数是不纯的。你在这里看到这是完全错误的。您可以根据需要随时调用 IO 函数,除了构造 IO 操作外,什么都不会发生。这是绝对纯净的。对于相同的参数,您将得到 "same"(就行为而言,因为我们无法比较它们)IO 操作返回,并且不会发生副作用 until这样的动作是实际执行的。

但是,您会问,为什么 callingMain1 函数中的 performUnsafe 什么都不做?这是因为 return 是懒惰的。根本没有理由评估它的论点。这也表明 performUnsafe 在 Frege 代码中确实是不安全的,并且关于何时以及以何种顺序对其进行评估的所有赌注都不成立。再举个例子,试试:

tail [IO.performUnsafe $ print "Ha"]

最后,calingMain2 这是最令人困惑的一个,我不确定你在这里想什么。 ST.run 将 运行 只有真正的 ST 幻像类型中多态的动作。现在,果然,你通过说

创建了这样一个 ST 动作
return IO.performUnsafe(main args)

ST.run 执行了 运行 此操作,结果评估了 performUnsafe

但是您不能将 ST.run 应用于 IO 操作。考虑

type IO = ST RealWorld
ST.run :: (forall s. ST s a) -> a

当你说:

ST.run(print "foo")

这行不通,因为 RealWorld 不像 s 那样多态。 幸运的是,你也不能在 Java 中使用它作弊,因为 Func<RealWorld,Short> 不是 Func<Object,Short>

的子类型

最后,我想重申一下:运行一个来自Java的IO action,除了传给performUnsafe

,没有别的办法

希望对您有所帮助,有什么不明白的可以随时提问。