mmhelloworld

main = println "Hello World!"

Idris JVM: Guarding against Java null using Maybe type

Idris JVM now helps avoiding nulls getting into Idris from FFI calls using Maybe type. FFI declarations can have Maybe type in any argument position or in the return type.

Handling null from FFI call

1
2
getProperty : String -> JVM_IO (Maybe String)
getProperty = invokeStatic SystemClass "getProperty" (String -> JVM_IO (Maybe String))

The above function is an FFI call to Java’s method static String getProperty(String key). The method returns a system property value if the property is set otherwise returns null. With Maybe type in the Idris function’s return type, the Idris function returns Nothing if the returned value is null otherwise the value is wrapped in Just.

Example
returningnull.idr
1
2
3
4
5
6
7
module Main

import IdrisJvm.IO
import Java.Lang

main : JVM_IO ()
main = printLn !(getProperty "foo")
1
2
3
4
5
6
7
$ idris --portable-codegen jvm -p idrisjvmffi returningnull.idr -o target

$ java -cp target:/path/to/idris-jvm-runtime-1.0-SNAPSHOT.jar main.Main
Nothing

$ java -cp target:/path/to/idris-jvm-runtime-1.0-SNAPSHOT.jar -Dfoo=hello main.Main
Just "hello"

Passing Maybe values for nullable values in FFI calls

passingnull.idr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module Main

import IdrisJvm.IO
import Java.Lang

namespace Component
  Component : Type
  Component = JVM_Native $ Class "java/awt/Component"

namespace JOptionPane
  JOptionPaneClass : JVM_NativeTy
  JOptionPaneClass = Class "javax/swing/JOptionPane"

  showMessageDialog : Inherits Object messageTy => Maybe Component -> messageTy -> JVM_IO ()
  showMessageDialog parent message =
    invokeStatic JOptionPaneClass "showMessageDialog" (Maybe Component -> Object -> JVM_IO ()) parent (believe_me message)

main : JVM_IO ()
main = showMessageDialog Nothing "Hello Idris!"

In the above code, the Java method JOptionPane.showMessageDialog(parentComponent, message) takes a nullable parent component and a message. If the parent component is null then the message is displayed in a default frame.

passingnull.idr
1
2
3
$ idris --portable-codegen jvm -p idrisjvmffi passingnull.idr -o target

$ java -cp target:/path/to/idris-jvm-runtime-1.0-SNAPSHOT.jar main.Main

Idris code passes Nothing in the above code so null is passed for the Java method that displays the message in a default frame as shown below.

Introducing Idris on the JVM and an Idris Android example

Idris on the JVM! Yes, a dependently typed language on the JVM! I have been working on a JVM bytecode backend for Idris for the past few months and it is now at a point that we can even write Android programs with Idris without having to write a single line of Java. In this post, we will see how Idris works on the JVM and an example Android program written in Idris.

Hello World

hellworld.idr
1
2
3
4
module Main

main : IO ()
main = printLn "Hello World"
Compile:
1
$ idris --portable-codegen jvm -p idrisjvmffi helloworld.idr -o target

Dependencies are provided as Idris packages, not as Java dependencies like jar or class files. The overall process is that the compiler reads Idris files and converts them into an intermediate JSON representation and the JVM bytecode generator takes the JSON files and converts them into JVM bytecode class files directly. It is only when we run a Java class, we have to provide Java dependency jars. The output option -o represents a directory where the Java class files will be created.

Run:
1
2
$ java -cp target:/path/to/idris-jvm-runtime-1.0-SNAPSHOT.jar main.Main
"Hello World"

And the output folder contains,

1
2
3
4
5
6
7
8
9
10
11
12
13
$ tree target
target
├── Decidable
│   └── Equality.class
├── main
│   └── Main.class
└── Prelude
    ├── Basics.class
    ├── Bool.class
    ├── Chars.class
    ├── Interfaces.class
    ├── Show.class
    └── Strings.class

Why do we have all these classes? We only compiled Main module! This is because Idris performs whole program analysis/compilation and code generator generates bytecode for all the modules that are relevant for the result produced by the main program.

How does Idris JVM handle tail calls?

Idris JVM eliminates self-recursion with JVM GOTO and uses trampolines for other tail calls. Let’s look at the following examples.

self-recursion example
selfrecursion.idr
1
2
3
4
5
6
7
8
9
10
11
12
module Main

import IdrisJvm.IO

sum : Nat -> Nat
sum n = go 0 n where
  go : Nat -> Nat -> Nat
  go acc Z = acc
  go acc n@(S k) = go (acc + n) k

main : JVM_IO ()
main = printLn (sum 50000)

This program would work just fine without blowing up the stack as it will be compiled down to a loop that uses JVM’s GOTO instruction. Here is the relevant section from bytecode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
$ javap -c -cp target:/path/to/idris-jvm-runtime-1.0-SNAPSHOT.jar main.Main

  public static java.lang.Object sum$whr$go$colon$0(java.lang.Object, java.lang.Object, java.lang.Object);
    Code:
       0: aconst_null
       1: astore        7
       3: aconst_null
       4: astore_3
       5: aconst_null
       6: astore        4
       8: aconst_null
       9: astore        5
      11: aconst_null
      12: astore        6
      14: iconst_1
      15: istore        8
      17: iload         8
      19: ifeq          130
      22: aload_2
      23: new           #80                 // class java/math/BigInteger
      26: dup
      27: ldc           #82                 // String 0
      29: invokespecial #85                 // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
      32: invokestatic  #333                // Method mmhelloworld/idrisjvmruntime/Util.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z
      35: ifeq          47
      38: aload_1
      39: astore        7
      41: iconst_0
      42: istore        8
      44: goto          127
      47: new           #80                 // class java/math/BigInteger
      50: dup
      51: ldc_w         #335                // String 1
      54: invokespecial #85                 // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
      57: astore_3
      58: aload_2
      59: invokestatic  #103                // Method mmhelloworld/idrisjvmruntime/Util.asBigInt:(Ljava/lang/Object;)Ljava/math/BigInteger;
      62: aload_3
      63: invokestatic  #103                // Method mmhelloworld/idrisjvmruntime/Util.asBigInt:(Ljava/lang/Object;)Ljava/math/BigInteger;
      66: invokevirtual #338                // Method java/math/BigInteger.subtract:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
      69: astore_3
      70: new           #80                 // class java/math/BigInteger
      73: dup
      74: ldc_w         #335                // String 1
      77: invokespecial #85                 // Method java/math/BigInteger."<init>":(Ljava/lang/String;)V
      80: astore        4
      82: aload_3
      83: invokestatic  #103                // Method mmhelloworld/idrisjvmruntime/Util.asBigInt:(Ljava/lang/Object;)Ljava/math/BigInteger;
      86: aload         4
      88: invokestatic  #103                // Method mmhelloworld/idrisjvmruntime/Util.asBigInt:(Ljava/lang/Object;)Ljava/math/BigInteger;
      91: invokevirtual #107                // Method java/math/BigInteger.add:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
      94: astore        4
      96: iconst_0
      97: invokestatic  #41                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     100: astore        5
     102: aload_1
     103: invokestatic  #103                // Method mmhelloworld/idrisjvmruntime/Util.asBigInt:(Ljava/lang/Object;)Ljava/math/BigInteger;
     106: aload         4
     108: invokestatic  #103                // Method mmhelloworld/idrisjvmruntime/Util.asBigInt:(Ljava/lang/Object;)Ljava/math/BigInteger;
     111: invokevirtual #107                // Method java/math/BigInteger.add:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
     114: astore        6
     116: aload         5
     118: astore_0
     119: aload         6
     121: astore_1
     122: aload_3
     123: astore_2
     124: goto          127
     127: goto          17
     130: aload         7
     132: areturn

The third line from the last is the GOTO instruction that transfers the control back to the top of function instead of actually calling the function.

Mutual recursion example:
mutualrecursion.idr
1
2
3
4
5
6
7
8
9
10
11
12
13
module Main

mutual
  evenT : Nat -> IO Bool
  evenT Z = pure True
  evenT (S k) = oddT k

  oddT : Nat -> IO Bool
  oddT Z = pure False
  oddT (S k) = evenT k

main : IO ()
main = printLn !(evenT 9999)

The above code also would work fine without killing the stack. Mutual recursion is handled using trampolines and the tail calls are delayed and compiled down to Java 8 lambdas. As the bytecode for this is bit long, here is the decompiled bytecode for the evenT function:

Decompiled bytecode for evenT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static Object evenT(Object var0) {
    Object var4 = null;
    Integer var1 = null;
    Integer var2 = null;
    IdrisObject var3 = null;
    if (Util.equals(var0, BigInteger.ZERO)) {
        var1 = Integer.valueOf(0);
        var2 = Integer.valueOf(0);
        var3 = new IdrisObject(1);
        var4 = new IdrisObject(65653, new Object[]{var1, var2, var3});
    } else {
        BigInteger var5 = BigInteger.ONE;
        var5 = Util.asBigInt(var0).subtract(Util.asBigInt(var5));
        var4 = () -> {
            return oddT(var5);
        };
    }

    return var4;
}

As we can see from the decompiled output above, the oddT call is not performed on the same call stack but a thunk wrapping the function call is returned using lambda (which is compiled down to JVM’s invokedynamic instruction).

Here is the relevant bit from bytecode for those who are interested:

bytecode for evenT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    68: getstatic     #64                 // Field java/math/BigInteger.ONE:Ljava/math/BigInteger;
    71: astore_1
    72: aload_0
    73: invokestatic  #68                 // Method io/github/mmhelloworld/idrisjvm/runtime/Util.asBigInt:(Ljava/lang/Object;)Ljava/math/BigInteger;
    76: aload_1
    77: invokestatic  #68                 // Method io/github/mmhelloworld/idrisjvm/runtime/Util.asBigInt:(Ljava/lang/Object;)Ljava/math/BigInteger;
    80: invokevirtual #72                 // Method java/math/BigInteger.subtract:(Ljava/math/BigInteger;)Ljava/math/BigInteger;
    83: astore_1
    84: aload_1
    85: invokedynamic #79,  0             // InvokeDynamic #1:call:(Ljava/lang/Object;)Lio/github/mmhelloworld/idrisjvm/runtime/Thunk;
    90: astore        4
    92: goto          95
    95: aload         4
    97: areturn

Java interoperability: Calling Java from Idris and calling Idris from Java

Idris JVM supports calling Java static methods, instance methods, constructors and also accessing static and instance fields from Idris. At the moment, except for Java arrays, all the Java types can be constructed from Idris and passed to Java methods. Support for handling nulls and exceptions is currently in progress and will soon be available. (Update 01/10/2017: We can now use Maybe type to avoid Java nulls in Idris code)

To use Idris functions from Java, Idris JVM supports exporting Idris functions as static methods, instance methods, constructors of an exported Java class. The exported class can also extend a Java class or implement interfaces with Idris functions.

To demonstrate these features, let’s create an Android application In Idris.

An Android application in Idris

idrisandroid.idr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
module Main

import IdrisJvm.IO
import Java.Lang

pythag : Int -> List (Int, Int, Int)
pythag max = [(x, y, z) | z <- [1..max], y <- [1..z], x <- [1..y],
                          x * x + y * y == z * z]

IdrisAndroidActivity : Type
IdrisAndroidActivity = JVM_Native $ Class "hello/IdrisAndroidActivity"

Bundle : Type
Bundle = JVM_Native $ Class "android/os/Bundle"

Context : Type
Context = JVM_Native $ Class "android/content/Context"

View : Type
View = JVM_Native $ Class "android/view/View"

TextView : Type
TextView = JVM_Native $ Class "android/widget/TextView"

Inherits View TextView where {}

CharSequence : Type
CharSequence = JVM_Native $ Class "java/lang/CharSequence"

Inherits CharSequence String where {}

superOnCreate : IdrisAndroidActivity -> Bundle -> JVM_IO ()
superOnCreate = invokeInstance "superOnCreate" (IdrisAndroidActivity -> Bundle -> JVM_IO ())

getApplicationContext : IdrisAndroidActivity -> JVM_IO Context
getApplicationContext = invokeInstance "getApplicationContext" (IdrisAndroidActivity -> JVM_IO Context)

newTextView : Context -> JVM_IO TextView
newTextView = FFI.new (Context -> JVM_IO TextView)

setText : Inherits CharSequence charSequence => TextView -> charSequence -> JVM_IO ()
setText this text = invokeInstance "setText" (TextView -> CharSequence -> JVM_IO ()) this (believe_me text)

setContentView : Inherits View view => IdrisAndroidActivity -> view -> JVM_IO ()
setContentView this view = invokeInstance "setContentView" (IdrisAndroidActivity -> View -> JVM_IO ()) this (believe_me view)

onCreate : IdrisAndroidActivity -> Bundle -> JVM_IO ()
onCreate this bundle = do
  superOnCreate this bundle
  context <- getApplicationContext this
  textView <- newTextView context
  setText textView $ "Hello Android from Idris! pythag 50 is " ++ show (pythag 50)
  setContentView this textView

main : IO ()
main = pure ()

androidExport: FFI_Export FFI_JVM "hello/IdrisAndroidActivity extends android/support/v7/app/AppCompatActivity" []
androidExport =
  Fun superOnCreate (Super "onCreate") $
  Fun onCreate (ExportInstance "onCreate") $
  End

The above program demonstrates calling Java instance methods (setText for example) and constructors (newTextView).

It further demonstrates how to handle inheritance relationship when passing subclass instances to a parent class type. For example, function setContentView takes a View but we can pass a TextView as it is a subclass of View and we mention that to Idris via Inherits View TextView where {}.

It also demonstrates how we can create a Java class that extends another class and override methods with Idris functions. The last section androidExport creates a Java class named hello/IdrisAndroidActivity that extends android/support/v7/app/AppCompatActivity. The Java class also creates a wrapper method superOnCreate that just delegates to super.OnCreate and the class also overrides onCreate method with Idris’ onCreate function. The Java class can also implement one or more Java interfaces with something like,

1
hello/IdrisAndroidActivity extends android/support/v7/app/AppCompatActivity implements java/lang/Runnable, java/lang/Comparable

A module can have multiple exports so we can actually create multiple Java classes with Idris implementation functions from an Idris module.

We can compile this as usual,

idris --portable-codegen jvm -p idrisjvmffi idrisandroid.idr -o target

It would produce the following class files:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ tree target/
target/
├── Decidable
│   └── Equality.class
├── hello
│   └── IdrisAndroidActivity.class
├── main
│   ├── Main.class
│   └── Prelude.class
└── Prelude
    ├── Algebra.class
    ├── Applicative.class
    ├── Bool.class
    ├── Foldable.class
    ├── Interfaces.class
    ├── List.class
    ├── Monad.class
    ├── Show.class
    └── Strings.class
Deploying to Android:
  1. Create an android project using Android studio with Jack support for Java 8.
  2. Then package the classes compiled above along with idris-jvm-runtime-1.0-SNAPSHOT.jar classes in a single jar and copy into an android project’s app/libs directory.
  3. Change the activity class name in android manifest file to the Idris exported class name hello.IdrisAndroidActivity.
  4. Then run ./gradlew installDebug from android project after starting an emulator or connected to an android device.
  5. Finally we should see our Idris code running on Android! It should look something like this:

Happy coding!

Haskell on the JVM via GHCJS and Nashorn

Currently there are 2 ways we can write Haskell on the JVM:

  1. Frege, a language that follows Haskell 2010 standard and compiles to Java.
  2. Haskell itself by compiling it to JavaScript via GHCJS.

Frege is basically a Haskell for the JVM and infact conforms to Haskell 2010 with few inbuilt GHC extensions. Even with good Java interop, it doesn’t sacrifice its type guarantees and currently is the only pure language on the JVM.

In this post, I am going to explore another interesting option: Haskell itself on the JVM. Haskell can be compiled to JavaScript using GHCJS and Java has an inbuilt JavaScript engine, called Nashorn so it is actually possible to compile Haskell to JavaScript and run the resulting JavaScript on the JVM.

Here is a simple Haskell code that can be run on the JVM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

module Main where

-- Nashorn doesn't provide default console object. Haskell's putStrLn logs to the console.
foreign import javascript unsafe "console={ \
    \ log: function(s) { java.lang.System.out.print(s); },\
    \ info: function(s) { java.lang.System.out.print(s); },\
    \ warn: function(s) { java.lang.System.out.print(s); },\
    \ debug: function(s) { java.lang.System.out.print(s); },\
    \ error: function(s) { java.lang.System.err.print(s); }\
    \ }"
  setupConsole :: IO ()

foreign import javascript unsafe "java.lang.System.exit($1)"
  sysexit :: Int -> IO ()

main = do
  setupConsole
  putStrLn "Hello from Haskell!"
  sysexit 0

Nashorn doesn’t have an inbuilt console object and Haskell’s putStrLn prints to the console so we have to provide an implementation of console. The implementation, as can be seen from the code above, is actually backed by Java’s System.out.print. That is our first example of calling Java from Haskell. sysexit is another function calling Java. sysexit is needed here as otherwise the program just keeps on running which I think is because of JavaScript event loop or something similar that prevents the JVM from shutting down.

Compiling Haskell with GHCJS and running on JVM

1
2
3
4
5
6
$ ghcjs -o HelloJava HelloJava.hs
[1 of 1] Compiling Main             ( HelloJava.hs, HelloJava.js_o )
Linking HelloJava.jsexe (Main)

$ jjs HelloJava.jsexe/all.js 
Hello from Haskell!

jjs is a JVM laucher for JavaScript code similar to Node. It is also possible to run this as a regular Java program along with other Java classes without jjs. jjs is just a convenient way to run just JavaScript code on the JVM. Above GHCJS compiles the Haskell code to JavaScript in one file all.js and the JVM runs the JavaScript code from all.js.

Example 2

Now let’s look at another example that shows how to convert between Haskell and Java lists:

Converstion between Haskell and Java Lists (HaskellJavaListsConversion.hs) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE JavaScriptFFI #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# LANGUAGE GHCForeignImportPrim #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE TypeFamilies #-}

module Main where

import Control.Monad.ST
import GHCJS.Types
import GHCJS.Foreign
import GHCJS.Prim
import Data.Typeable
import GHC.ST

data MutabilityType s = Mutable
                      | Immutable
                      | STMutable s

data IsItMutable = IsImmutable
                 | IsMutable

-- Copied from GHCJS.Internal.Types. Not sure why this is not exposed.
type family Mutability (a :: MutabilityType s) :: IsItMutable where
  Mutability Immutable     = IsImmutable
  Mutability Mutable       = IsMutable
  Mutability (STMutable s) = IsMutable

{- java.util.ArrayList class and its methods -}
newtype SomeArrayList (a :: MutabilityType s) = SomeArrayList JSVal deriving Typeable
type ArrayList           = SomeArrayList Immutable
type MutableArrayList    = SomeArrayList Mutable
type STArrayList s      = SomeArrayList (STMutable s)

instance IsJSVal (SomeArrayList m)

-- ArrayList Constructor
foreign import javascript unsafe "new $1()"
  arrayList_new :: JType -> ST s (STArrayList s)

-- Adds an element to ArrayList
foreign import javascript unsafe "$2.add($1)"
  arrayList_add :: JSVal ->  STArrayList s -> ST s ()

{- java.util.Iterator class and its methods -}
newtype SomeIterator (a :: MutabilityType s) = SomeIterator JSVal deriving Typeable
type Iterator            = SomeIterator Immutable
type MutableIterator     = SomeIterator Mutable
type STIterator s        = SomeIterator (STMutable s)

instance IsJSVal (SomeIterator m)

-- Create an Iterator from an ArrayList
foreign import javascript unsafe "$1.iterator()"
  iterator :: STArrayList s -> ST s (STIterator s)

foreign import javascript unsafe "$1.hasNext()"
  iterator_hasNext :: STIterator s -> ST s Bool

foreign import javascript unsafe "$1.next()"
  iterator_next :: STIterator s -> ST s JSVal

{- Other Nashorn imports -}

-- Represents a Java type
newtype JType = JType JSVal

foreign import javascript unsafe "java.lang.System.out.println($1)"
  jprintln :: JSVal -> IO ()

foreign import javascript unsafe "java.lang.System.exit($1)"
  sysexit :: Int -> IO ()

-- Imports a Java class
foreign import javascript unsafe "Java.type($1)"
  jimport :: JSVal -> JType

{- Create an instance of Java's ArrayList from Haskell's list -}
listToArrayList :: [JSVal] -> ST s (STArrayList s)
listToArrayList xs = do
    let arrayListClass = jimport $ toJSString "java.util.ArrayList"
    arrList <- arrayList_new arrayListClass
    go xs arrList
  where
    go [] arrList = return arrList
    go (x:xs) arrList = do
      arrayList_add x arrList
      go xs arrList

{- Create Haskell's list from Java's Iterator -}
iteratorToList :: STIterator s -> ST s [JSVal]
iteratorToList itr = reverse <$> go [] where
  go acc = do
    hasNext <- iterator_hasNext itr
    if hasNext
      then do
        next <- iterator_next itr
        go (next: acc)
      else
        return acc

-- Nashorn doesn't provide default console object. Haskell's putStrLn logs to the console.
foreign import javascript unsafe "console={ \
    \ log: function(s) { java.lang.System.out.print(s); },\
    \ info: function(s) { java.lang.System.out.print(s); },\
    \ warn: function(s) { java.lang.System.out.print(s); },\
    \ debug: function(s) { java.lang.System.out.print(s); },\
    \ error: function(s) { java.lang.System.err.print(s); }\
    \ }"
  setupConsole :: IO ()

demo = runST $ do
  jlist <- listToArrayList . map toJSInt $ [1..5]
  iterator jlist >>= iteratorToList

main = do
  setupConsole
  mapM_ (putStrLn . show . fromJSInt) demo
  sysexit 0

In the code above, two Java types are used: java.util.ArrayList and java.util.Iterator.

Importing a Java class

A Java class can be imported with Java.type(className) Nashorn JavaScript code. Line 80 defines the corresponding Haskell FFI function:

1
2
3
-- Imports a Java class
foreign import javascript unsafe "Java.type($1)"
  jimport :: JSVal -> JType

Creating an instance of a Java class

An instance can be created by invoking the constructor on the Java class with new. Here is the corresponding FFI:

1
2
3
-- ArrayList Constructor
foreign import javascript unsafe "new $1()"
  arrayList_new :: JType -> ST s (STArrayList s)

It takes the ArrayList class and invokes the dafault ArrayList constructor to return an instance of it. In the same way, we can create FFI functions for ArrayList.add and ArrayList.iterator to return an Java Iterator instance.

The function listToArrayList takes a Haskell list and return an instance of Java ArrayList. As the java list is mutable, it is returned as STArrayList s inside ST. This function first creates an instance of ArrayList by invoking the Java constructor and then calls ArrayList.add to add items from Haskell list to the ArrayList.

In the similar way, the function iteratorToList takes a Java iterator and returns Haskell list by extracting items from the iterator by invoking corresponding FFI functions for Iterator.hasNext and Iterator.next.

Building with Stack

It is easy to setup a GHCJS project with Stack so that we can add other dependencies easily and build it for GHCJS. With the above code in a stack project “haskell-jvm-hello”, we can build it with stack build and run it with jjs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ stack build
haskell-jvm-hello-0.1.0.0: unregistering (local file changes: app/Main.hs)
haskell-jvm-hello-0.1.0.0: build
Preprocessing library haskell-jvm-hello-0.1.0.0...
In-place registering haskell-jvm-hello-0.1.0.0...
Preprocessing executable 'haskell-jvm-hello-exe' for
haskell-jvm-hello-0.1.0.0...
[1 of 1] Compiling Main             ( app/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0_ghcjs/build/haskell-jvm-hello-exe/haskell-jvm-hello-exe-tmp/Main.js_o )
Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0_ghcjs/build/haskell-jvm-hello-exe/haskell-jvm-hello-exe.jsexe (Main)
haskell-jvm-hello-0.1.0.0: copy/register
Installing library in
/workspace/haskell-jvm-hello/.stack-work/install/x86_64-linux/lts-3.12/ghcjs-0.2.0_ghc-7.10.3/lib/x86_64-linux-ghcjs-0.2.0-ghc7_10_3/haskell-jvm-hello-0.1.0.0-7MA0h74rERuEwiJY2TRuHx
Installing executable(s) in
/workspace/haskell-jvm-hello/.stack-work/install/x86_64-linux/lts-3.12/ghcjs-0.2.0_ghc-7.10.3/bin
Warning: the following files would be used as linker inputs, but linking is not being done: .stack-work/dist/x86_64-linux/Cabal-1.22.4.0_ghcjs/build/haskell-jvm-hello-exe/haskell-jvm-hello-exe
Registering haskell-jvm-hello-0.1.0.0...

$ jjs .stack-work/dist/x86_64-linux/Cabal-1.22.4.0_ghcjs/build/haskell-jvm-hello-exe/haskell-jvm-hello-exe.jsexe/all.js
1
2
3
4
5

Java’s Nashorn JavaScript engine opens up few more ways for the JVM to be polyglot and it is so good to have one of the best languages, Haskell, on the JVM. Actually it should also be possible to run PureScript as well in this way on the JVM but that is for another day. Happy Haskelling!

Frege: Record accessors and mutators

Frege has built-in mechanism to access and mutate (non-destructive) record fields.

Consider the following type in Frege:

1
2
3
4
5
frege> data Point = Point {x :: Int, y :: Int}
data type Point :: *

frege> derive Show Point
instance Show  Point

Now we can use the following functions to get and set record fields:

1
2
3
4
5
6
7
8
frege> Point.x
:: Point -> Int

frege> Point.{x = }
:: Point -> Int -> Point

frege> Point.{x <- }
:: Point -> (Int->Int) -> Point

For Field x,

  1. The function Point.x is the getter.
  2. The function Point.{x = } is a setter which sets the field x with a new value.
  3. The function Point.{x <- } is also a setter but applies a function to update the current value.

We can use the functions like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
frege> p = Point 3 4
value p :: Point

frege> p
Point 3 4

frege> Point.x p
3

frege> Point.{x =} p 13
Point 13 4

frege> Point.{x <-} p (+15)
Point 18 4

Frege also provides some shortcuts to apply these functions:

1
2
3
4
5
6
7
8
9
10
11
frege> p.x -- Same as `Point.x p`
3

frege> p.{x = 10} -- Same as `Point.{x = } p 10`
Point 10 4

frege> p.{x <-} -- Same as `Point.{x <-} p`
:: (Int->Int) -> Point

frege> p.{x <- (+10)} -- Same as `Point.{x <- } p (+10)`
Point 13 4

Multiple updates can be combined:

1
2
frege> p.{x <- (+8), y = 20} -- Increment x by 8 and set y to 20
Point 11 20

Accessors and updates can be at any level deep. Let’s create another type:

1
2
3
4
5
6
7
8
9
10
frege> :{
> data Circle = Circle {center :: Point, radius :: Int}
>
> derive Show Circle
> :}

data type Circle :: *
instance Show  Circle

frege>

Here we have an aggregate type Circle which composes another type Point for it’s field center. Now we can update and select fields at different levels:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
frege> c = Circle {center = Point 4 5, radius = 10}
value c :: Circle

frege> c
Circle (Point 4 5) 10

frege> c.center.x
4

frege> c.{center <- Point.{x = 8}}
Circle (Point 8 5) 10

frege> c.{center <- Point.{y <- (+20)}, radius <- (*5)}
Circle (Point 4 25) 50

In the latest version, Frege provides syntactic sugar for lambdas using underscores. For example, T.foo can be written as _.foo if the type can be deduced from the context the lambda is applied. Hence the following two are equivalent.

1
2
3
4
5
frege> c.{center <- Point.{x = 25}}
Circle (Point 25 5) 10

frege> c.{center <- _.{x = 25}}
Circle (Point 25 5) 10

Frege provides another utility to check for a field’s existence. This would be useful if we have multiple constructors with different set of fields.

1
2
3
4
5
6
7
8
9
10
11
frege> :{
> data Point = Point2d {x :: Int, y :: Int}
>            | Point3d {x :: Int, y :: Int, z :: Int}
>
> derive Show Point
> :}

data type Point :: *
instance Show  Point

frege>

In the above code, we have two constructors Point2d and Point3d where the field z exists only for Point3d. We can check for the existence of field z like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
frege> Point.{z?}
:: Point -> Bool

frege> hasZ = Point.{z?}

frege> hasZ $ Point3d 3 4 5
true

frege> hasZ $ Point2d 3 4
false

frege> p = Point3d 3 4 5
value p :: Point

frege> p.{z?}
true

For more details on how these field existence check, accessor and mutator functions are generated for a record type, here is the link to Frege language reference: http://www.frege-lang.org/doc/Language.pdf.

Happy coding!

Frege: Hello Java

Here is a small code demonstrating Java interoperability in Frege:

Calling Java from Frege (HelloJava.fr) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
module hellojava.HelloJava where

data LinkedList a = native java.util.LinkedList where
    native add :: Mutable s (LinkedList a) -> a -> ST s Bool
    native get :: Mutable s (LinkedList a) -> Int -> ST s (Maybe a) throws
        IndexOutOfBoundsException
    native new :: () -> STMutable s (LinkedList a)

    fromFregeList :: [a] -> STMutable s (LinkedList a)
    fromFregeList xs = LinkedList.new () >>= loop xs where
        loop (x:xs) jlist = LinkedList.add jlist x >> loop xs jlist
        loop [] jlist = return jlist

plusTop :: Mutable s (LinkedList Int) -> ST s (Maybe Int)
plusTop xs = do
    a <- xs.get 0
    b <- xs.get 1
    return ((+) <$> a <*> b)

data IndexOutOfBoundsException = native java.lang.IndexOutOfBoundsException
derive Exceptional IndexOutOfBoundsException

data Exception = native java.lang.Exception
derive Exceptional Exception

data NullPointerException = native java.lang.NullPointerException
derive Exceptional NullPointerException

pure native showThrowable toString :: Throwable -> String

main _ = do
    javaList <- LinkedList.fromFregeList [1, 2, 3]
    try (\xs -> plusTop xs >>= (println . maybe "Got a null pointer" show)) javaList
        `catch` (\(npe :: NullPointerException) -> println $ showThrowable npe)
        `catch` (\(exception :: Exception) -> println $ showThrowable exception)

We can observe the following things from the above code:

  1. Making use of a Java class and its methods
  2. Using a Java object in a Frege function
  3. Using Java Exceptions in functions
  4. Handling Java exceptions

1. Making use of a Java class and its methods:

If a Java class is pure then without much effort, we can use that class in Frege. For example,

1
2
3
4
data Integer = native java.math.BigInteger where
    pure  native abs                                  :: Integer -> Integer
    pure  native negate                               :: Integer -> Integer
    pure  native valueOf java.math.BigInteger.valueOf :: Long -> Integer

A Java class is declared with data declaration in Frege. The identifier after the data keyword is the corresponding type for the Java class in Frege and the qualified Java class is identified after the native keyword followed by the instance methods, static methods or even some Frege functions not defined in the original Java class.

An important point here is that the instance methods on BigInteger take Integer as their first argument which is the this reference on which the methods will be invoked.

Coming back to our original example, here we are trying to use the mutable Java class java.util.LinkedList. An obvious difference between this one and the BigInteger example is that the functions now do not have the pure keyword in front.

The next difference is that the instance methods now cannot take the simple type like LinkedList a as we did for Integer but the type is now Mutable s (LinkedList a) since it is not a pure function. If we don’t annotate a native function pure and we don’t use Mutable to consume or return a mutable Object, it will be a compilation error. Mutable objects can only be used in ST or IO actions so the return type must be in ST or IO monad.

The LinkedList.add() method returns a boolean. Since it is an impure function, it should be used in ST monad. Here the boolean itself is pure so it is just ST s Bool. Take a look at the third function new, LinkedList constructor. This function is impure and it returns a mutable object, a new LinkedList instance, so the return type is ST s (Mutable s (LinkedList a)) for which the shorthand is STMutable s (LinkedList a).

Here is an example for a native function not being part of a native data declaration. This is useful when a native class is already declared in Frege in some module but the function that we are looking for is missing in the data declaration.

1
pure native showThrowable toString :: Throwable -> String

Here showThrowable is the Frege function name for Throwable.toString(). Since it is an instance method on Throwable, the first argument is of type Throwable and then the formal arguments’ types (in this case, none) and return type.

2. Using a Java object in a Frege function

A native data declaration doesn’t have to just contain the native members, it can also have additional Frege functions. In our example, the function fromFregeList is not defined in the Java class but it has been added as an utility function to create a LinkedList from a frege list. Here again the same rule as in the previous section applies: To return a mutable Java object, we should use ST s (Mutable s TheJavaType) which is nothing but STMutable s TheJavaType.

In the same way, the plusTop function takes a mutable Java object so the parameter type is Mutable s (LinkedList Int). Also since it consumes a mutable type, it must be in ST monad hence the return type is ST s (Maybe Int) returning an Maybe Int in ST.

3. Using Java Exceptions in functions

To use a Java Exception class, it must be first defined in a Frege module. It is the same as declaring native declaration for a Java class but additionally we need to derive the Exceptional type class so that the exception can later be handled with catch.

1
2
3
data IndexOutOfBoundsException = native java.lang.IndexOutOfBoundsException

derive Exceptional IndexOutOfBoundsException

The exceptions can then be used in native declarations as in get function in our example:

1
2
native get :: Mutable s (LinkedList a) -> Int -> ST s (Maybe a) throws
    IndexOutOfBoundsException

4. Handling Java exceptions

In two ways, we can handle exceptions:

  1. Using action `catch` handler1 `catch` handler2

    The type of catch is Exceptional β => ST γ α -> (β->ST γ α) -> ST γ α.

    Here the action is the code where an exception might be thrown and the handlers handler1 and handler2 take an exception and return another value in ST monad. The infix notation facilitates adding multiple handlers with better readability. Further here the handler1 must be more specific(in terms of the types of the exceptions being handled) than handler2. Also note that from Frege standard library with respect to catch:

    Note If action is of the form: doSomething arg then, depending on the strictness of doSomething the argument arg may be evaluated before the action is returned. Exceptions (i.e. undefined values) that occur in the construction of the action do not count as exceptions thrown during execution of it, and hence cannot be catched.

    Example: println (head []) `catch` ....

    will not catch the exception that will be thrown when println evaluates

    For a remedy, see try.

  2. Using try

    First, the type: try :: Monad γ => (α-> γ β) -> α -> γ β

    Unlike catch, try takes a function that produces a monadic value. If the function can throw an exception, it must result in an ST monad which can then be passed to catch to handle those exceptions. In our example, \xs -> plusTop xs >>= (println . maybe "Got a null pointer" show) is the function which when applied to a java.util.LinkedList might throw a NullPointerException or IndexOutOfBoundsException:

Using try
1
2
3
4
    try (\xs -> plusTop xs >>= (println . maybe "Got a null pointer" show)) javaList
        catch` (\(npe :: NullPointerException) -> println $ showThrowable npe)
        catch` (\(exception :: Exception) -> println $ showThrowable exception)

Since the construction of action is deferred through a lambda here, try eliminates the issue with catch mentioned in the above note.

Extending a class or implementing an interface in Frege:

One thing that is not shown in the example is extending a Java class or implementing an interface in Frege. Unfortunately both are not possible in Frege yet. There is a workaround though using a Java class which extends a class or implements an interface but instead of an implementation on its own, it just delegates to a Frege function. For example, see here for implementing java.lang.Runnable in Frege using a Java class frege.runtime.SwingSupport which takes a Frege function and then delegates to it in run method implementation.

This concludes our little experimentation calling Java from Frege. The other interesting side, calling Frege from Java, is for a future post.