Saturday, October 13, 2012

New Features in Frege

Now, that the holiday season is over, I'll hopefully have to announce interesting news regarding Frege more often.

As the short note from last week indicates, the project has now moved to Github. The fregIDE has been separated and is now a project on its own. There is ongoing work on a continuous integration facility. The result will be that there will be no "offiicial" releases any more. Rather, certain versions will be merely marked as stable, while all friends of frege will be able to download the more recent builds also.

Even if it may have seemed so, we were not completely idle since the Easter Release. Besides numerous bug fixes, the following new features are now available:

  1. Record fields can now be polymorphic
  2. The restrictions regarding instances of function types have been dropped.
  3. As a further step to more Haskell compatibility, a single dot can now be used as function composition operator.
For more explanations and examples please consult the new wiki page that is devoted to new or changed features.

Sunday, October 7, 2012

Frege moved to GitHub

We moved the frege project permanently to GitHub

Thursday, April 5, 2012

2012 Easter Release

I am happy to announce availability of Frege release 3.19.112 which is now ready for download. This has been made possible with the help of our contributors; two of them joined us since the last release. Many thanks to all of you, guys!

Here is a brief overview of what has changed.

Language/Compiler
Some changes have been made to reduce the generated code in size and number of classes, while at the same time making the compiler a bit faster. The decrease in size is noticeable, for example, the new frege3.19.112.jar is now 7MB, this is 3MB smaller than its predecessor, despite code has been added in the libraries and elsewhere.
The compiler now on request in-lines functions that have been marked as inline candidates, see the Language Reference, Chapter 4 for details. This feature is still considered experimental, in no case should in-lining change anything but memory requirements and running time of the resulting program. Should you observe such misbehavior, I'd love to hear about it.
Note that in-lining is restricted to functions that are "easy" enough. The compiler will give you a warning if you mark a function as inline candidate that it feels is not appropriate. In addition, the effect of "too much" in-lining could well be slower running times, because the JIT may have a harder time to compile larger byte code methods. There is just not enough experience here.

The syntax of the if statement has changed so as to allow the following:

    do
        if condition
        then action1
        else if other condition then other action
        else error "you blew it"

Technically, (one) semicolon is allowed, but not required, before else and then.

Library
Thanks to the many contributions, I cannot enumerate everything that has been changed and added. I can only hope that everything is well documented. Complaints, questions and proposals are best addressed in our discussion group.

fregIDE
The eclipse plugin had enhancements in the outline view and new features: editor actions, mouse-over information and mouse-over navigation. Please consult the tutorial for details.

Future Developments
We are working on an interpreter/REPL.
The library will evolve continuously. For one part, experience shows that porting Haskell source code is straightforward unless unsupported GHC extensions are needed. But also the interface to common Java APIs is on the agenda.
The compiler and type system will evolve further. Enhancements in the field of type classes are envisioned.
And the eclipse plugin will surely see more funky features.





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.

Friday, January 6, 2012

A source of inconvenience removed

Unqualified variable names in Frege source code are looked up in the innermost lexical scope. If the name is not found there, the next higher scope is tried, until the search arrives at the top level name space.

If the variable appeared in an expression that lives in the where clause of an instance, class or data declaration, this is no different, just that the corresponding name space is searched before the top level.

This simple, logical approach that does not require special code for special cases has some unfortunate consequences, though. Consider:

data T = T Int

instance Show T where
    show (T i) = "T " ++ show i

Here, the show on the right hand side resolves to the show just being defined, and this takes arguments of type T, not Int.  This results in a type error:

E Test.fr:6: type error in expression i
    type is   Int
    used as   T

But this is not the worst case yet. It can bite also when one defines something completely different, like in the following (admittedly slightly contrived) example:

data T a = T a where
   isNegative :: T a  -> Bool
   isNegative (T x) = (show x).charAt 0 == '-'

derive Eq    T a
derive Show  T a

This gives the following seemingly unjustified errors from the type checker:

E Test.fr:5: type `T t3496` is not as polymorphic as suggested 
    in the annotation where just `a` is announced.
E Test.fr:5: type error in expression x
    type is   a
    used as   T t3496
E Test.fr:5: type error in expression
    charAt (show x) 0
    type is   Char
    used as   T t3495
E Test.fr:5: type error in expression
    '-'
    type is   Char
    used as   T t3495
E Test.fr:5: inferred type is more constrained than expected type
    inferred:  (Eq t3495,Show t3497) => T a -> Bool
    expected:  T a -> Bool

The reason is that the derive declarations silently populate the name space T with definitions for show and == among others. Hence the local x must be of type (T b), due to appearing as argument of T's show. Likewise, the (==) insists on taking two T's.


The workaround is to qualify all class operations that should not resolve to the type specific incarnations introduced by instance declarations (note that derive declarations are just expanded to instance declarations). Hence, correct ways to write the definition in the first example are:

show (T i) = "T " ++ i.show

or

show (T i) = "T " ++ Int.show i

or even

show (T i) = "T " ++ Show.show i

Experience has shown that this is an error one commits again and again. From user feedback I know that it's not just me. Everybody trained in Haskell will most likely fall into that trap.
Therefore, in order to make it more convenient and more Haskell compatible and because I am tired from explaining that it works as designed, the following rule has recently been implemented when resolving simple identifiers:
If a simple name resolves to an implementation of a type class operation in some instance and the same name, if used on the top level, would resolve to a type class operation, then this name resolves to the said type class operation, thereby skipping the lexical scope of the enclosing data or instance where clause.
With this rule, the examples above will be automagically interpreted so as if  all class operations were qualified with the name of the class that introduced them. This makes the program acceptable to the type checker.

Note that this change does not break existing code. Such code will have employed one of the 3 workarounds shown above, but  the qualified notation remains of course still valid, and is unaffected by the new rule. Existing code is just slightly more explicit and verbose than needed, that's all.

The changed compiler is available in versions greater 3.18.108.