Как Java может записывать команды в GHCi?

Я создаю приложение (Windows), используя Haskell для реализации числовых методов решения проблем и Java для графического интерфейса и обработки пользовательского ввода. Для межпроцессного взаимодействия я заставляю их читать и записывать в общий файл JSON. Все это работает, но при попытке выполнить программу, связавшись с Java с cmd и запустив GHCi, я не могу загрузить и запустить файл Haskell после запуска компилятора. Сообщения об ошибках нет, но моя Java-программа часто оказывается в тупике. Есть идеи? Вот мой код:

        try {
            // Serialize dataMap to JSON and write to file
            String jsonString = objectMapper.writeValueAsString(dataMap);
            FileWriter fileWriter = new FileWriter("newtonRaphson.json");
            fileWriter.write(jsonString);
            fileWriter.close();

            // Read JSON file
            File jsonFile = new File("newtonRaphson.json");
            JsonNode rootNode = objectMapper.readTree(jsonFile);

            // Extract solution from JSON
            Iterator<Map.Entry<String, JsonNode>> fields = rootNode.fields();
            Map.Entry<String, JsonNode> secondEntry = fields.next();
            JsonNode solutionOut = secondEntry.getValue();
            String solutionText = solutionOut.asText();

            // Display equation on GUI
            Text messageTextFxn = new Text(equation);
            messageTextFxn.setFont(new Font("System", 15));
            fxnPane.getChildren().add(messageTextFxn);

            // Display solution on GUI
            Text messageTextSol = new Text(solutionText);
            messageTextSol.setFont(new Font("System", 15));
            solPane.getChildren().add(messageTextSol);

            // Launch Haskell REPL and interact with it
            String haskellPath = "path\\to\\hsFile";
            ProcessBuilder builder = new ProcessBuilder("stack", "repl");
            builder.redirectInput(ProcessBuilder.Redirect.INHERIT);
            builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
            builder.redirectError(ProcessBuilder.Redirect.INHERIT);
            Process process = builder.start();

            OutputStream outputStream = process.getOutputStream();
            PrintWriter writer = new PrintWriter(outputStream);
            
            // Load Haskell module
            writer.println(":l " + haskellPath + "\\newtonRaphson");
            writer.flush();
            System.out.println("Haskell module loaded successfully.");

            // Execute Haskell function
            writer.println("nr");
            writer.flush();
            System.out.println("Haskell function executed successfully.");

            // Close writer and wait for process to terminate
            writer.close();
            int exitCode = process.waitFor();

            if (exitCode == 0) {
                System.out.println("Process completed successfully.");
            } else {
                System.out.println("Process terminated with an error.");
            }

Я пробовал использовать разные способы взаимодействия с терминалом, включая ProcessBuilder и Runtime exec(), но я думаю, что это, вероятно, неправильный подход, просто не знаю, что делать на этом этапе.

Вы запускаете команду «стек». Это командная строка Haskell? Не можете ли вы скомпилировать файл Haskell и запустить его напрямую по имени?

Tim Roberts 16.03.2024 05:14

@TimRoberts, командная строка Haskell — GHCi, но я получаю к ней доступ, запуская стек и вводя REPL. Я пробовал запустить файл Haskell напрямую с помощью Runtime exec() и, возможно, я делаю что-то неправильно, но у меня пока это не сработало.

atoa 16.03.2024 05:24

Я согласен, реплика предназначена для интерактивного использования человеком. Если вы хотите, чтобы программа взаимодействовала с другой программой, скомпилируйте ее и выберите реальный протокол связи, который они будут использовать.

amalloy 16.03.2024 05:36

@amalloy, так ты думаешь, мне следует сосредоточиться на компиляции и запуске программы напрямую через Java? Насколько я знаю, для компиляции файлов Haskell требуется GHC, поэтому мне придется найти способ заставить Java запускать файл Haskell после того, как Java заставит компьютер скомпилировать его с помощью GHC. Я обдумывал такой подход, но, честно говоря, понятия не имею, как мне его реализовать.

atoa 16.03.2024 05:42

Зачем использовать Java для его компиляции? Похоже, что в вашем примере вы не пишете файлы на Haskell на лету, поэтому просто скомпилируйте их один раз, и ваш графический интерфейс будет взаимодействовать с скомпилированной программой.

amalloy 16.03.2024 05:44

Также кажется странным использовать INHERIT, когда вы хотите управлять вводом-выводом подпроцесса вручную. Это действительно так? Если я правильно читаю документацию, INHERIT означает, что его входные и выходные данные должны быть такими же, как у родительского процесса.

amalloy 16.03.2024 05:47

@amalloy, что вы имеете в виду под написанием файлов Haskell на лету? Идея состоит в том, чтобы в конечном итоге иметь возможность импортировать проект, поэтому я бы предпочел, чтобы пользователь не компилировал вручную каждый файл Haskell при запуске приложения. Или, может быть, есть способ скомпилировать их все каким-то другим способом? Может быть, через другой язык?

atoa 16.03.2024 05:48

@amalloy, устранив методы перенаправления и вместо этого используя bufferedWriter, сработало, большое спасибо за помощь!

atoa 16.03.2024 06:00

«Насколько мне известно, для компиляции файлов Haskell требуется GHC, поэтому мне придется найти способ заставить Java запускать файл Haskell после того, как Java заставит компьютер скомпилировать его с помощью GHC». Вы не компилируете его с помощью Java, вы компилируете его независимо, а затем запускаете его, как и любую другую исполняемую программу, с помощью ProcessBuilder.

Louis Wasserman 19.03.2024 21:22
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
9
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Подробности см. в обсуждении ОП, но устранение методов с использованием INHERIT и вместо этого использование bufferedWriter сработало:

 try {
        // Serialize dataMap to JSON and write to file
        String jsonString = objectMapper.writeValueAsString(dataMap);
        FileWriter fileWriter = new FileWriter("newtonRaphson.json");
        fileWriter.write(jsonString);
        fileWriter.close();

        // Read JSON file
        File jsonFile = new File("newtonRaphson.json");
        JsonNode rootNode = objectMapper.readTree(jsonFile);

        // Extract solution from JSON
        Iterator<Map.Entry<String, JsonNode>> fields = rootNode.fields();
        Map.Entry<String, JsonNode> secondEntry = fields.next();
        JsonNode solutionOut = secondEntry.getValue();
        String solutionText = solutionOut.asText();

        // Display equation on GUI
        Text messageTextFxn = new Text(equation);
        messageTextFxn.setFont(new Font("System", 15));
        fxnPane.getChildren().add(messageTextFxn);

        // Display solution on GUI
        Text messageTextSol = new Text(solutionText);
        messageTextSol.setFont(new Font("System", 15));
        solPane.getChildren().add(messageTextSol);

        // Launch Haskell REPL and interact with it
        String haskellPath = "C:\\Users\\cezar\\Desktop\\AcademicResources\\Engineering\\Java\\JavaFX_VS\\chemesolver\\haskell\\nr\\src";
        ProcessBuilder builder = new ProcessBuilder("stack", "repl");
        Process process = builder.start();

        OutputStream outputStream = process.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
        
        // Load Haskell module
        writer.write(":l " + haskellPath + "\\newtonRaphson");
        writer.flush();
        System.out.println("Haskell module loaded successfully.");

        // Execute Haskell function
        writer.write("nr");
        writer.flush();
        System.out.println("Haskell function executed successfully.");

        // Close writer and wait for process to terminate
        writer.close();
        int exitCode = process.waitFor();

Другие вопросы по теме