javahaskellipccommunication

How can Java write commands to the GHCi?


I'm making an application (Windows) using Haskell to implement numerical methods to solve problems and Java for the GUI and to process user input. For inter-process communication, I'm having them both read from and write to a mutual JSON file. It all works, but when attempting to execute the program by having Java communicate with cmd and run the GHCi, I can't seem to load and run the Haskell file once the compiler is running. There is no error message, but my Java program seems to often end up in what I think is deadlock. Any ideas? Here's my code:

        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.");
            }

I've tried using different ways to actually communicate with the terminal including processBuilder and Runtime exec(), but I'm thinking this is probably the wrong approach, just not sure what to do at this point.


Solution

  • See the discussion on the OP for details, but eliminating the methods using INHERIT and instead using bufferedWriter worked:

     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();