Thursday, February 9, 2012

Using mutable java types and non-pure methods

For those of my high esteemed readers who suffer from the not yet completed chapter 6 of the Frege language reference that is supposed to explain the native interface, I'll give a small example program today that makes use of a supposedly mutable java type and some impure java methods.

The program prints the current date and time to the standard output every other second and runs until terminated through external means.

{-- 
    This program displays the
    current time on stdandard output
    every other second.
    -}
    
module examples.CommandLineClock where

data Date s = native java.util.Date where
    native new :: () -> ST s (Date s)           -- new Date()
    native toString :: Date s -> ST s String    -- d.toString()

This data declaration introduces the java class java.util.Date as abstract data type for Frege under the name Date. Objects of this class are mutable, hence we will use this type in the ST monad (or in the IO monad, which is just a special ST monad). We want to employ the safety the ST monad gives us, hence Date is indexed by a phantom type s that will always match that of the ST action.

Because Date is an abstract data type, we can't do anything with it unless we have functions that take or return values of that type. It is natural (but not required) to define such functions in the body of the data declaration.
Unsurprisingly, the functions we provide for Date are themselves native ones, or, in other words, they are java methods. We merely inform the Frege compiler about their existence and  at what type we want to use them.
The Date.new function will be an ST action that calls the parameter-less constructor of the java.util.Date class and gives us Date values to work with. The java constructor will initialize the Date value with the current time.
The Date.toString function will be an ST action that calls the toString method of a Date value.

It may not be obvious, but the types of the Date functions and the properties of the ST monad will make it impossible to do anything malicious with Date values. It will not be possible, for instance, to run a ST action, obtain a Date value, keep it around in pure data structures and pass it later to another, totally unrelated ST action. (To understand why, you'll want to read the paper Lazy Functional State Threads, for now, take my word for it.)

We are now in a position to write an ST action that computes the current time as a string, where "current" means the time when the action is actually performed:
--- 'ST' action to give us the current time as 'String'
current :: ST s String      -- works also in the IO monad
current = do
    d <- Date.new ()
    d.toString

We said our program will print the current time every other second, but this is just another way to say it will do nothing 99.999% of the time. It's actually quite hard for a computer program to do nothing (even for a lazy one), but to our luck we have the whole Java API at our disposal. For example, in the class java.lang.Thread, we find the following method:

public static void sleep(long millis)
                  throws InterruptedException

The corresponding java documentation states:
Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.
Parameters:
millis - the length of time to sleep in milliseconds
Throws:
IllegalArgumentException - if the value of millis is negative
InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.
The only problem left is to make this function known to Frege in an appropriate way, and this means to translate the method signature to a sensible Frege type.
The java type long maps to Long, and void to (), but we must also take care of the possible exception.
In addition, it is obvious that this is not going to be a pure function!
{- 
    Encoded in Frege:
    - argument type  long   Long
    - result         void   ()
    - throws ...            Exception ()
    - does IO               IO (Exception ()) 
-}
native sleep java.lang.Thread.sleep :: Long -> IO (Exception ())

The native declaration above in plain English: When n is of type Long, sleep n will be an IO action that, when executed, calls the java method java.lang.Thread.sleep with the argument n, catches any exception that my happen and returns a value of type Exception (). (Since we're ignoring the returned value, we'll not deal with Exception today.)

Now that we have everything we need, the main action couldn't be easier:
main args = 
    forever do
        current >>= print
        print "\r"
        sleep 999L

Try it out, it works!

The alert reader will have noticed, that the type of Date.new is actually wrong. The idea is, that an ST action may employ impure operations, as long as the overall result is pure and referentially transparent. Specifically, if a is a ST action, then
ST.run a

should be a pure value. This is unfortunately not the case for our
ST.run current

because its value depends on the time of evaluation.
The cause of this is that we erred about the type of Date.new.
Because its underlying Java code somehow accesses the timer, it is an IO action in reality.
Hence we must write:
native new :: () -> IO (Date RealWorld)

We also need to change
current :: IO String

While it makes no difference in our small program, it teaches us a lesson of how scrupulous one must be with the types of native functions! If, for example, the semantics of the java constructor was to initialize the object with some fixed time value, then the given type was correct.

The (corrected) code can be found, along with other example code on the project source page.

Monday, February 6, 2012

Library Support

I devoted the last weeks mainly to advance the development of the standard libraries.

Data.List, Data.Maybe

The release 3.19.9 that is ready for download now contains a Data.List  module almost compatible with the Haskell 2010 report and the Prelude has the same list functions as the Haskell Prelude; and, in addition, makes available all that is in Haskell's Data.Maybe.
The remaining incompatibilities have to do with the fact that String is not [Char] in Frege, hence list functions do not work on Strings.
There is an easy way to make lists of characters from Strings, and it works the same for any other type whose values that can be viewed as lists. Technically, this is achieved through a type class ListSource with method toList that is supposed to turn its argument into a list lazily. Currently, [a], String and Maybe a are instances of ListSource, arrays will be added later and of course you can make instances for your own types.
The ListSource type class is employed in list comprehension generators: one can write any expression that has a type which is an instance of ListSource on the right hand side of an arrow.
The functions nullhead, ++ and tail are also class operations for ListLike types, and they work on Strings and normal lists. This makes is possible to write functions that work on lists, Strings and every other instantiated type without conversion of the value to a list.

Monadic functions and type classes

The prelude has now a hierarchy of monad related type classes that adapts the one proposed in The Other Prelude. However, the traditional names like fmap, <*>, etc. have been kept. And, because pure is a keyword in Frege, the corresponding operation lives under the name  return in  Applicative.

We can instantiate a whole class hierarchy with a single instance declaration in Frege, hence there is no need to have explicit separate Functor, Applicative and Monad instances when one needs a MonadZero, for example.

The functions and classes provided by the Frege Prelude are a superset of what is in the Haskell 2010 Prelude `union`  Control.Monad.

Other libraries

Thanks to Daniel Gronaus efforts (who also advocated and proof-of-concepted the monadic code, see above) we now have the Floating class (import frege.prelude.Floating to use it) and the modules Control.Monoid, Control.NonEmpty and Control.Foldable.

Haskellish Module Names

A Frege module name is at the same time the fully qualified Java name of the class the compiler creates as result of the compilation of the module. The package part of that name should consist of all lowercase identifiers according to Java customs.
But as seen in the paragraphs above, we can now use module names like Data.Maybe.
For compatibility reasons, the compiler will accept such names in package clauses as well as import clauses, but transform them a bit to arrive nevertheless at a more or less javaish correct class name:

{--
    When a package name consists of more than just a 'CONID' 
    and the first character is an uppercase letter, then this 
    letter is replaced by its lowercase equivalent and the
    string @"frege."@ prepended to form the real package name.
    
    > magicPack "Data.List" = "frege.data.List"
    > magicPack "List"      = "List"  
    -}
magicPack (nm@´\.´)
    | fst.isUpperCase = "frege." ++ fst.toLowerCase.display ++ tail nm
    where 
        fst = String.charAt nm 0
magicPack nm = nm

Note that such classes will always live in some Java package whose name starts with frege. Hence this  feature is intended for use with very well known standard libraries. Please follow Java conventions for naming your own packages.

fregIDE
The fregIDE now has an outline view. This makes navigating in a bigger-than-a-screenful source file much easier.