5

I'm trying to create a program to compare the amount of time it takes various haskell scripts to run, which will later be used to create graphs and displayed in a GUI. I've tried to create said GUI using Haskell libraries but I haven't had much luck, especially since I'm having trouble finding up to date GUI libraries for Windows. I've tried to use Java to get these results but either get errors returned or simply no result.

I've constructed a minimal example to show roughly what I'm doing at the moment:

    import java.io.*;
public class TestExec {
    public static void main(String[] args) {
        try {
            Process p = Runtime.getRuntime().exec("ghc test.hs 2 2");
            BufferedReader in = new BufferedReader(
                                new InputStreamReader(p.getInputStream()));
            String line = null;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

And here is the Haskell script this is calling, in this case a simple addition:

test x y =  x + y

Currently there simply isn't any result stored or printed. Anyone have any ideas?

6
  • Create executable first and then run it in exec Commented Dec 9, 2013 at 15:23
  • You also need a main in your haskell code. Commented Dec 9, 2013 at 15:25
  • You are telling Haskell that test x y is the same as x + y. What output do you expect? Commented Dec 9, 2013 at 15:36
  • You should also use runghc rather than ghc Commented Dec 9, 2013 at 15:43
  • Such benchmark won't produce any reliable results. 'Test' function executes instantly. Thus your benchmark will only measure how long does it take in your OS to start an executable. Commented Dec 10, 2013 at 11:31

4 Answers 4

3

Since you're attempting to run this as an executable, you need to provide a main. In you're case it should look something like

import System.Environment

test :: Integer -> Integer -> Integer
test = (+)

main = do
  [x, y] <- map read `fmap` getArgs
  print $ x `test` y

This just reads the command line arguments, adds them, then prints them. Though I did something like a while ago, it's much easier to do the benchmarking/testing in Haskell, and dump the output data to a text file in a more structured format, then parse/display it in Java or whatever language you like.

Sign up to request clarification or add additional context in comments.

3 Comments

I get an error when trying to compile this: Couldn't match type [Char] with Char, Expected type IO String, Actual type IO [String] (in the second argument of fmap). I had considered having one Haskell script do all the benchmarking etc for each other script in the directory, but wasn't sure if it would be simpler than this way or not. I'll probably look back into that though, thanks for the tip
Thanks. Another quick question that I didn't think warranted another full question: Using a variation of the code posted above I want to read two arguments but one is a string and the other an integer, however I get type mismatch errors when compiling. Is there a way to tell haskell to read X as an Int and y as a String?
@fylth remove the map read part and instead of test x y do test (read x) y
2

This is mostly a Java question. Search for Runtime.getRuntime().exec().

On the Haskell side, you need to write a stand-alone Haskell script. The one by @jozefg is OK. You should be able to run it as

runghc /path/to/script.hs 1 2

from the command line.

Calling it from Java is no different than running any other external process in Java. In Clojure (a JVM language, I use it for brevity) I do:

user=> (def p (-> (Runtime/getRuntime) (.exec "/usr/bin/runghc /tmp/test.hs 1 2")))
#'user/p
user=> (-> p .getInputStream input-stream reader line-seq)
("3")

Please note that I use runghc to run a script (not ghc). Full paths are not necessary, but could be helpful. Your Java program can be modified this way:

--- TestExec.question.java
+++ TestExec.java
@@ -2,7 +2,7 @@
 public class TestExec {
     public static void main(String[] args) {
         try {
-            Process p = Runtime.getRuntime().exec("ghc test.hs 2 2");
+            Process p = Runtime.getRuntime().exec("/usr/bin/runghc /tmp/test.hs 2 2");
             BufferedReader in = new BufferedReader(
                                 new InputStreamReader(p.getInputStream()));
             String line = null;

The modified version runs the Haskell script just fine. You may have to change paths to you runghc and test.hs locations.

Comments

0

At first to read from output you need to use OutputStreamReader(p.getOutputStream()) instead of InputStreamReader

Comments

0

As I said in comment such a benchmark is simply incorrect. While benchmarking one should eliminate as many side coasts as possible. The best solution is to use the criterion package. It produces nice graphical output as you desire.

Small example:

import Criterion
import Criterion.Main
import Criterion.Config

fac 1 = 1
fac n = n * (fac $ n-1)

myConfig = defaultConfig {
              cfgReport = ljust "report.html"
             }

main = defaultMainWith myConfig (return ()) [
           bench "fac 30" $ whnf fac 30
          ]

After execution it produces a file "report.html" with neat interactive plots.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.