First of all sorry for my English, and for the fact that I'm trying to learn Haskell
I would run Frege code (Haskell) calling from java, for almost all aspects I managed to make it all work as per instructions found on various sites ... but I still have a question about the following code, and sorry for the wordiness of the request ...
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 (GENERATED from 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 ... }
}
Program output ... with entry point: local.java.JavaHelloTtest.main
------------------
Hello World from Java code ...
========================
callingMain0 ...
------------------------
Hello World from Frege code ...
========================
callingMain1 ...
------------------------
========================
callingMain2 ...
------------------------
Hello World from Frege code ...
========================
and after long (for me) survey I realized it is right that "CallingMain1" does not perform anything ... in fact, as you can see generated by the "callingMain2" needs a "run" ... but if I try to execute, with a "run", what comes back "callingMain1" IDE (Eclipse and then the compiler) tells me that the signature is incorrect, PreludeBase.TST.<Short>run is on "Object" and not on "RealWorld", in fact, the compiler in the case of "callingMain2" sets a "Object" and not a "RealWorld" to run callingMain2.
obviously (I think) the signature (Haskell) of "callingMain1" is correct ... and I think no one can touch ...
and now the question ... at this point I think, perhaps, it should be a function ... TST.runOnRealWorld allowing assessment IO () returned from yet "callingMain1"; however, as in the generation of "callingMain2" I clearly see that the operation is changed on-the-fly on "Object" I have to assume that this function does not exist ...
this is wanted or just need to add a "run" method that allows java to evaluate the output of "callingMain1" ?
or, more likely, I understood very little ... Thanks a lot in advance ...
First, I'd like to say there is no need to be sorry for trying to learn Haskell. To the contrary. Consider yourself as belonging to the elite, insead!
The java code generated for
callingMain0is the right one to run an I/O action from Java. I recommend to use that directly (or through a Java utility method) and not have a seemingly pure helper function likecallingMain0for hygienic reasons.By the way, when you pass a value that has a Frege algebraic data type (except for enumerations) you don't need to wrap it in an extra
Thunk.<...>lazy()since all those types already implement theLazyinterface. So you can write:This works regardless whether the function actually expects a lazy list or a strict one.
Next,
callingMain1Of course, it does nothing, just likewould do nothing. Why? Because the type is
IO ()This type tells us that the function returns an action that will yield a()when that action is executed. And the only way to execute an IO action in Frege is throughPreludeBase.TST.<T>performUnsafe. But you don't pass the action (that is, the result of callingcallingMain1(...)) toperformUnsafe. Hence, the action is never performed.Remark: When you examined the code generated for your Frege module, you have maybe noticed the presence of a
mainmethod. If not, look it up. You'll see that themainmethod that is entered by the JVM just calls$main(which corresponds to your Fregemainfunction) by passing its result toperformUnsafe. There simply is no other way.Yet another remark: There is a widely shared misconception, namely that Haskell (or Frege) functions with
IOtype are impure. You see here that this is outright wrong. You can callIOfunctions as often as you want, and nothing will ever happen, except that anIOaction is constructed. This is absolutly pure. For the same arguments, you'll get the "same" (in terms of behaviour, as we can't compare them)IOaction back, and no side effect will happen until such actions are actually performed.But, you'll ask, why did the
performUnsafeinside thecallingMain1function do nothing? This is becausereturnis lazy. There's simply no reason to evaluate its argument. This also shows thatperformUnsafeis indeed unsafe in Frege code, and all bets are off regarding when and in what order it will be evaluated. For another example, try:Finally,
calingMain2This is the most confusing one, and I'm not sure what you were thinking here.ST.runwill run only genuineSTactions that are polymorphic in the phantom type. Now, sure enough, you created such aSTaction by sayingand
ST.rundid run this action, which resulted in evaluating theperformUnsafe.But you can't apply
ST.runtoIOactions. ConsiderWhen you say:
this won't work, because
RealWorldis not as polymorphic ass. And luckily, you can't cheat with it in Java either, sinceFunc<RealWorld,Short>is not a subtype ofFunc<Object,Short>Finally, I want to re-iterate: To run an IO action from Java, there is no other way than to pass it to
performUnsafeHope this helps, feel free to ask about things that are not clear yet.