Как оценить / запустить монаду frege IO () из Java?
Прежде всего, извините за мой английский и за то, что я пытаюсь выучить Haskell
Я бы запустил код Фреге (Haskell), звонящий из java, для почти всех аспектов мне удалось заставить все это работать согласно инструкциям, найденным на различных сайтах... но у меня все еще есть вопрос по поводу следующего кода, и извините за многословность запрос...
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" ничего не выполняет... на самом деле, как вы видите, генерируемый "callMain2" нуждается в "запуске"... но если я попытаюсь Выполнение, с "run", то, что возвращается "вызывает Main1" IDE
(Eclipse и затем компилятор), говорит мне, что подпись неверна, PreludeBase.TST.
очевидно (я думаю) подпись (Haskell) для "CallMain1" является правильной... и я думаю, что никто не может коснуться...
а теперь вопрос... на данный момент я думаю, что, возможно, это должна быть функция... TST.runOnRealWorld, позволяющий оценивать IO (), возвращенный из пока еще "callMain1"; однако, как и в генерации "CallMain2", я ясно вижу, что операция "на лету" изменяется на "Объекте". Я должен предположить, что эта функция не существует...
это нужно или просто нужно добавить метод "run", который позволяет java оценивать вывод "callMain1"?
или, скорее, я очень мало понял... Заранее большое спасибо...
1 ответ
Во-первых, я хотел бы сказать, что нет необходимости сожалеть о попытке выучить Хаскель. Иначе. Считайте себя принадлежащим к элите, инсэд!
Java-код, сгенерированный для callingMain0
является правильным для запуска действия ввода-вывода из Java. Я рекомендую использовать это непосредственно (или через метод утилит Java) и не иметь, казалось бы, чистой вспомогательной функции, такой как callingMain0
по гигиеническим причинам.
Кстати, когда вы передаете значение, имеющее алгебраический тип данных Фреге (за исключением перечислений), вам не нужно оборачивать его в дополнительный Thunk.<...>lazy()
поскольку все эти типы уже реализуют Lazy
интерфейс. Таким образом, вы можете написать:
FregeHelloTest.callingMain0(PreludeArrays.IListSource_JArray.<String>toList(args));
Это работает независимо от того, ожидает ли функция ленивый или строгий список.
Следующий, callingMain1
Конечно, это ничего не делает, так же, как
FregeHelloTest.$main(...)
не будет ничего делать Зачем? Потому что тип IO ()
Этот тип говорит нам, что функция возвращает действие, которое приведет к ()
когда это действие выполнено. И единственный способ выполнить IO-действие во Фреге - через PreludeBase.TST.<T>performUnsafe
, Но вы не пропустите действие (то есть результат вызова callingMain1(...)
) чтобы performUnsafe
, Следовательно, действие никогда не выполняется.
Примечание: когда вы изучали код, сгенерированный для вашего модуля Frege, вы, возможно, заметили наличие main
метод. Если нет, посмотрите. Вы увидите, что main
метод, который вводится JVM просто вызывает $main
(что соответствует вашему Фреге main
функция), передав его результат performUnsafe
, Другого пути просто нет.
Еще одно замечание: существует широко распространенное заблуждение, а именно, что Хаскелл (или Фреге) функционирует с IO
типа нечисты. Вы видите здесь, что это совершенно неправильно. Ты можешь позвонить IO
функционирует так часто, как вы хотите, и ничего не произойдет, кроме того, что IO
действие построено. Это абсолютно чисто. За те же аргументы вы получите "то же самое" (с точки зрения поведения, поскольку мы не можем их сравнить) IO
действие назад, и никакого побочного эффекта не произойдет, пока такие действия фактически не будут выполнены.
Но вы спросите, почему performUnsafe
внутри callingMain1
функция ничего не делает? Это потому что 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<RealWorld,Short>
не является подтипом Func<Object,Short>
Наконец, я хочу повторить: чтобы выполнить действие ввода-вывода из Java, нет другого способа, кроме как передать его performUnsafe
Надеюсь, это поможет, не стесняйтесь спрашивать о вещах, которые еще не ясны.