【问题标题】:How to evaluate/run frege IO () monad from java?如何从 java 评估/运行 frege IO () monad?
【发布时间】:2017-03-20 14:17:34
【问题描述】:

首先对不起我的英语,以及我正在努力学习 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$1) {
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>*/> η$7611) {
                   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, η$7611.call());
                               }
                             }
                           );
                 }
               },
               Thunk.<String/*<Character>*/>lazy("Hello World from Frege code ...")
             ).call();
   }

final public static short callingMain2(final Lazy<PreludeBase.TList<String/*<Character>*/>> arg$1) {
  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$1));
                          }
                        }
                      )
                )
          ).call();
}

final public static Func.U<RealWorld, Short> callingMain1(final Lazy<PreludeBase.TList<String/*<Character>*/>> arg$1) {
  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$1));
                    }
                  }
                )
          );
}

final public static short callingMain0(final Lazy<PreludeBase.TList<String/*<Character>*/>> arg$1) {
  return (short)PreludeBase.TST.<Short>performUnsafe(FregeHelloTest.$main(arg$1)).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”生成需要一个“运行”......但如果我尝试 通过“运行”执行返回的“callingMain1”IDE (Eclipse 然后是编译器)告诉我签名不正确, PreludeBase.TST.运行在“Object”而不是“RealWorld”上, 事实上,编译器在“callingMain2”的情况下设置了一个 运行 callMain2 的“对象”而不是“真实世界”。

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

现在的问题......在这一点上,我认为,也许,它应该是 一个函数... TST.runOnRealWorld 允许评估 IO() 从尚未“callingMain1”返回;然而,就像在一代 “callingMain2”的我清楚地看到操作发生了变化 在“对象”上即时运行我必须假设这个函数不存在......

这是想要的,或者只需要添加一个“运行”方法 允许java评估“callingMain1”的输出?

或者,更可能的是,我了解的很少......提前非常感谢......

【问题讨论】:

    标签: frege


    【解决方案1】:

    首先,我想说没有必要为尝试学习 Haskell 而感到抱歉。从相反的方面来说。认为自己属于精英,欧洲工商管理学院!

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

    顺便说一句,当您传递具有 Frege 代数数据类型(枚举除外)的值时,您不需要将其包装在额外的 Thunk.&lt;...&gt;lazy() 中,因为所有这些类型都已经实现了 Lazy 接口。所以你可以写:

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

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

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

    FregeHelloTest.$main(...) 
    

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

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

    还有一句话:有一个普遍存在的误解,即 IO 类型的 Haskell(或 Frege)函数是不纯的。你在这里看到这是完全错误的。您可以根据需要随时调用IO 函数,除了构造IO 操作之外,什么都不会发生。这绝对是纯粹的。对于相同的参数,您将得到“相同”(在行为方面,因为我们无法比较它们)IO 动作,并且不会发生副作用直到这样的动作实际执行。

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

    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&lt;RealWorld,Short&gt; 不是 Func&lt;Object,Short&gt; 的子类型

    最后,我想重申一下:要从 Java 运行 IO 操作,除了将其传递给performUnsafe之外别无他法

    希望对您有所帮助,有不清楚的地方可以随时提问。

    【讨论】:

    • 非常感谢,我还有不少东西要研究
    • 当然,感谢 (Frege lang) 的出色工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 2011-09-29
    • 1970-01-01
    • 2011-11-28
    相关资源
    最近更新 更多