State in CAL

5 views
Skip to first unread message

mega...@gmail.com

unread,
Nov 1, 2007, 8:23:53 AM11/1/07
to CAL Language Discussion
I'm new to the CAL language. I've downloaded Open Quark and have done
some testing with the Eclipse plugin. So far I'm impressed with the
tools and the documentation available.

I'm currently evaluating functional programming languages for the JVM
as a replacement for Java and so far Scala and CAL seem to be the best
options. One thing I like about Scala is that it supports functional
programming while still making it easy to handle mutable state like in
Java. This is very nice when for example programming GUIs.

In the CAL examples included in Open Quark the state is "hidden"
inside Java objects which you import, but how would you implement
state in pure CAL? I'm interested in implementing a mutable properties
library, an event library etc. I don't have much experience with
Haskell, but if I'm not mistaken it's normally implemented as state
monads and "do"-notation, but CAL doesn't seem to support "do"-
notation.

Any examples of stateful CAL programs or pointers to such information
would be appreciated.

--
Regards,
Jesper Nordenberg

Bo Ilic

unread,
Nov 1, 2007, 4:50:49 PM11/1/07
to CAL Language Discussion
Hi Jesper,

There are various approaches to handling state in CAL, and I'll try to
summarize them here without trying to drown you in detail. Let me know
if you'd like more info on any of these as your investigations
proceed.

1. The fundamental pure-functional approach to state is to pass the
state through as an extra argument of the functions involved, with the
'updated' state then returned as part of the return result of the
function. This is not mutation though- both the original argument and
its updated value remain available. An example of this is the
updateLookupWithKey function in the Map module which updates the
argument map, returning it as the second component of the result pair.
updateLookupWithKey :: Ord k => (k -> a -> Maybe a) -> k -> Map k a ->
(Maybe a, Map k a);
There are many simpler examples where the result is basically the
updated value.
update :: Ord k => (a -> Maybe a) -> k -> Map k a -> Map k a;
Many functions in the List module are of this sort as well.

2. A fancier pure-functional approach involves state monads, or their
equivalent. The basic idea is that you can use a type that threads
through the extra state argument so that it doesn't have to be an
explicit argument in all your functions. Examples of this are in the
Parser module in CAL with the treatment of the GenParser type. In
Haskell this type is an instance of the Monad type class, and we could
have done the same in CAL, but didn't mainly due to historical reasons
(our Monad type class postdated the GenParser type). However, it
functions in the same way, and is an example of this technique.

3. Another approach is to encapsulate state within the Java
application. The simplest example of this is the
org.openquark.cal.samples.EventLoop sample that comes with Open Quark.
A more involved example with UI is the BAM (Business Activity Monitor)
Sample application included with Open Quark. The Gem Cutter is another
(rather more involved) instance of this approach as well. Also, there
is a thread in comp.lang.functional that talks about this case of
mixed language programming.
http://groups.google.com/group/comp.lang.functional/browse_thread/thread/6cfcab5b9d0b5566/0e58f9e4cea69d86#0e58f9e4cea69d86
This can be an important option for larger projects.

4. You've already seen examples of mutating state held by values of a
foreign Java type. The mutating functions need not be foreign
functions (although they are ultimately built-up out of them). The
ideal is to make these functions pure functions eventually by
encapsulating the mutation, as in the implementation of the
Prelude.outputListWith and Prelude.inputListFromJObject functions.
There are also many examples in the implementations of the shootout
benchmarks in CAL available here: http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=all.
CAL makes this reasonably convenient to do correctly, even though it
is a lazy language, via plinging of function arguments, and the
Prelude.seq function. These are explained in detail in the Effective
CAL document available in the distribution.

5. It is also possible to not encapsulate the state in a pure-
functional way. Examples of this are the sample Plot module, and its
use in the CellularAutomata sample module.

6. An approach to session-level state (such as for example, the
TimeZone or Locale in which a computation is occurring) is to pass it
through the execution context using the ExecutionContextProperties
Java class. These properties can be accessed in CAL via the System
module.

7. It is actually possible to mutate a CAL value, appropriately
wrapped. An example of this is the 'MutableVariable a' type defined in
the Chameneos benchmark sample.

8. Another approach to look at in the libraries involves the use of
the CalFunction type. This can be used to define a pure-
transformation, which is then evaluated on some state held by an
enclosing stateful Java object. For example, the sortByExternal_Alt ::
(a -> a -> Ordering) -> [a] -> [a]; defined in the Prelude_Tests
module illustrates this approach. This function implements a CAL sort
of immutable lists, by marshaling the CAL list to a Java list, sorting
using the in-place mutable Java list, using the CAL comparison
function for the comparison, and marshaling back to a CAL list.

Cheers,
Bo

mega...@gmail.com

unread,
Nov 2, 2007, 7:27:13 AM11/2/07
to CAL Language Discussion
Thanks for the detailed reply.

> 7. It is actually possible to mutate a CAL value, appropriately
> wrapped. An example of this is the 'MutableVariable a' type defined in
> the Chameneos benchmark sample.

I implemented a solution similar to this one and it works fine. I
created a simple Java class wrapping a mutable field with get and set
methods, and then created CAL functions using input, output, to CAL
value and from CAL value.

Some other questions that has popped up:

- How do you handle Java interfaces in CAL, for example if you want to
implement an ActionListener?

- Operator overloading (as in Haskell) would be really nice, for
example to replace `seq` with an easier to type operator. Is this
something that is planned for future versions?

- Are type synonyms and "newtype" supported? If not, any plans to add
them in the future?

Also, I might have found a bug. I tried to import a Java class called
test.Var but then I got string index out of bounds -1. When I changed
it to test.x.Var it worked fine. I can provide more detailed
information if needed.

--
Regards,
Jesper Nordenberg

Joseph Wong

unread,
Nov 2, 2007, 8:47:02 PM11/2/07
to cal_la...@googlegroups.com
Hi Jesper,

I've tried reproducing your problem with importing a Java class named
test.Var as a foreign type in CAL, but have not encountered the out of
bounds exception. Would you mind sending more details (to this mailing
list) about how it failed for you? That would be much appreciated!

Thanks,
Joseph

Bo Ilic

unread,
Nov 2, 2007, 9:29:16 PM11/2/07
to CAL Language Discussion
On Nov 2, 4:27 am, megagu...@gmail.com wrote:
> Some other questions that has popped up:
>
> - How do you handle Java interfaces in CAL, for example if you want to
> implement an ActionListener?

For a Java interface with 1 method (it can be generalized though), the
idea is to marshal a CAL function to a Prelude.CalFunction, and write
a Java class that holds the CalFunction as a field, and implements the
Java interface. The implementation of the method then delegates to the
CalFunction.evaluate() method.

An example of this is in the Prelude_Tests module in the
implementation of the sortByExternal_Alt function. In its
implementation, a function creating a Java comparator (i.e.
implementing the java.util.Comparator interface)
(a -> a -> Ordering) -> Comparator
is defined via the composition of a function (a -> a -> Ordering) ->
CalFunction, and a function CalFunction -> Comparator.

>
> - Operator overloading (as in Haskell) would be really nice, for
> example to replace `seq` with an easier to type operator. Is this
> something that is planned for future versions?
>
> - Are type synonyms and "newtype" supported? If not, any plans to add
> them in the future?

We have no current plans for adding these Haskell features to CAL, but
here are some comments/questions.

It is easy to add particular operators by modifying the compiler
implementation. Are there any particular functions (or class methods)
that you'd like an operator form for? What symbols would you like to
use for them? The general purpose facility of Haskell makes great tool
support difficult since these operators can have user-defined
precedence and associativity.

The Haskell newtype feature is pretty much the same as having a data
declaration with a single data constructor holding a single plinged
field.
e.g. AnotherMaybe is a 'newType' of Maybe
data AnotherMaybe a = AnotherMaybe v :: !(Maybe a);

For foreign types, there is also another approach e.g. basically
AnotherString is a 'newtype' of String.
data foreign unsafe import jvm "java.lang.String" AnotherString;

Cheers,
Bo

mega...@gmail.com

unread,
Nov 3, 2007, 1:00:49 PM11/3/07
to CAL Language Discussion
On Nov 3, 2:29 am, Bo Ilic <bo.i...@businessobjects.com> wrote:
> It is easy to add particular operators by modifying the compiler
> implementation. Are there any particular functions (or class methods)
> that you'd like an operator form for? What symbols would you like to
> use for them? The general purpose facility of Haskell makes great tool
> support difficult since these operators can have user-defined
> precedence and associativity.

If you do stateful programming `seq` is used often so it would be nice
if it could be replaced with an operator. `seq` is similar to the ";"
operator in Scala in that evaluates two expressions and returns the
result of the second. Maybe it's possible to implement a simpler
version of operator overloading similar to the one used in Scala.
There every operator has a fixed precedence and associativity, but the
programmer can still define new operators (or redefine existing ones).

Type synonyms would useful, for example:

type MyRecord = {name :: String, age :: Int};

mega...@gmail.com

unread,
Nov 3, 2007, 5:00:10 PM11/3/07
to CAL Language Discussion
On Nov 3, 1:47 am, "Joseph Wong" <Joseph.W...@businessobjects.com>
wrote:

> I've tried reproducing your problem with importing a Java class named
> test.Var as a foreign type in CAL, but have not encountered the out of
> bounds exception. Would you mind sending more details (to this mailing
> list) about how it failed for you? That would be much appreciated!

Below is a small CAL and Java example that that reproduces the bug. In
the ICE console just write "var (10 :: Int)". When I change the Java
package name to test.x it works fine.

ICE error:

Error while executing: Fatal Executor error.
Caused by: java.lang.StringIndexOutOfBoundsException: String index out
of range: -1, Detail: String index out of range: -1

Stack trace:

java.lang.StringIndexOutOfBoundsException: String index out of range:
-1
at java.lang.String.substring(String.java:1938)
at
org.openquark.cal.internal.machine.lecc.CALToJavaNames.getModuleNameFromPackageName(CALToJavaNames.java:
733)
at
org.openquark.cal.internal.machine.lecc.CALClassLoader.findClass(CALClassLoader.java:
287)
at
org.openquark.cal.internal.machine.lecc.CALClassLoader.loadClass(CALClassLoader.java:
467)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
at org.openquark.cal_MyModule1.Var.f1S(Var.java)
at org.openquark.cal_MyModule1.Iceruntarget.f(Iceruntarget.java)
at org.openquark.cal.internal.runtime.lecc.RTFullApp$General
$_0.reduce(RTFullApp.java:225)
at
org.openquark.cal.internal.runtime.lecc.RTResultFunction.unsynchronizedEvaluate(RTResultFunction.java:
136)
at
org.openquark.cal.internal.runtime.lecc.RTResultFunction.evaluate(RTResultFunction.java:
103)
at
org.openquark.cal_MyModule1.Io__iceruntarget__0__0.f(Io__iceruntarget__0__0.java)
at org.openquark.cal.internal.runtime.lecc.RTFullApp$General
$_0.reduce(RTFullApp.java:225)
at
org.openquark.cal.internal.runtime.lecc.RTResultFunction.unsynchronizedEvaluate(RTResultFunction.java:
136)
at
org.openquark.cal.internal.runtime.lecc.RTResultFunction.evaluate(RTResultFunction.java:
103)
at org.openquark.cal_Cal_Core_Prelude.Id.f(Id.java)
at
org.openquark.cal.internal.runtime.lecc.RTApplication.reduce(RTApplication.java:
156)
at
org.openquark.cal.internal.runtime.lecc.RTResultFunction.unsynchronizedEvaluate(RTResultFunction.java:
136)
at
org.openquark.cal.internal.runtime.lecc.RTResultFunction.evaluate(RTResultFunction.java:
103)
at
org.openquark.cal.internal.machine.lecc.Executor.exec(Executor.java:
173)
at org.openquark.cal.ICE$FunctionRunThread.run(ICE.java:7226)
at java.lang.Thread.run(Thread.java:619)


CAL source:
------------------------------------------------------------
module MyModule1;

import Cal.Core.Prelude using
typeClass = Eq, Inputable, Outputable;
typeConstructor = JObject, Unit;
function = output, toCalValue;
;

data foreign unsafe import jvm public "test.Var"
public JVar deriving Inputable, Outputable, Eq;

foreign unsafe import jvm "constructor test.Var" private jVar_new ::
JObject -> JVar;

data public Var a = private Var value :: !JVar deriving Inputable,
Outputable, Eq;

var :: a -> Var a;
var !value =
Var (jVar_new $ output $ toCalValue value);
------------------------------------------------------------

Java source:
------------------------------------------------------------
package test;

public class Var {
private Object value;

public Var(Object v) {
value = v;
}
}
------------------------------------------------------------

Edward

unread,
Nov 5, 2007, 2:19:44 PM11/5/07
to CAL Language Discussion
Hi Jesper,
This is indeed a bug -- thanks for providing details.
Some code that parses out periods needed to have an extra check.
We'll make sure it gets fixed.

In the meantime, of course a work around is to make sure that your
imported classes have two or more package segments. :)

Thanks,
- Edward

Bo Ilic

unread,
Nov 7, 2007, 12:44:17 AM11/7/07
to CAL Language Discussion

On Nov 3, 9:00 am, megagu...@gmail.com wrote::


>
> Type synonyms would useful, for example:
>
> type MyRecord = {name :: String, age :: Int};

Hi Jesper.

For the example you gave, the suggested approach in CAL would be to
declare a new type:
data MyRecord = MyRecord value :: !{name :: String, age :: Int};
This has the advantage of enabling one to use shorter type names in
functions involving MyRecord types, without the problems associated
with type synonyms such as poor error messages (since it is just a
heuristic whether to display a type or its synonym when an error
occurs), problems with mistakenly using the synonym in code when that
wasn't intended, or forgetting to use it when it was, etc.

Where efficiency is particularly important and people writing Haskell
tend to write type synonyms for primitive types such as Int (e.g. say
Key as a synonym of Int), the CAL approach of creating a foreign type
with the same implementation type as Int. and converting to and from
that type (e.g. Int -> Key and Key -> Int) via foreign function cast
declarations actually generates the identical compiled CAL code as
just using the single Int type, but has the type safety benefits of
distinguishing a Key and an Int.

The type synonym feature of Haskell may have been influenced by the
earlier precedent of typedefs in C. On the other hand, CAL was
influenced by the lack of typedefs in Java. It is possible to see this
problem both ways, but given that the workarounds basically produce
nicer more type-safe code, we found the disadvantages of type synonyms
to be greater than the advantages.

Cheers,
Bo

helmut

unread,
Nov 16, 2007, 5:06:32 PM11/16/07
to CAL Language Discussion
hi

i want to test the cal <-> java example from Jesper - i make a jar
file with the java code - with JFit (add jar file) i can import - what
is the trick that the CAL-Compiler find the jar?

helmut

mb

unread,
Nov 16, 2007, 7:17:16 PM11/16/07
to CAL Language Discussion
Hi Helmut,

To add extra jars you must make sure they are on the Java classpath.
If you are using the command line, e.g. ICE.sh, GemCutter.sh,
quarkc.sh, the easiest way to do this is to create a new file set-
javacp-extended.sh in the Quark installation directory, which contains
the extra jars, e.g:
JAVACP_PATH=$JAVACP_PATH:/home/magnus/mystuff.jar

(On windows you would need to create a set-javacp-extended.bat that
contains:
set JAVACP_PATH=%JAVACP_PATH%;c:/mystuff.jar)

If you are using Eclipse with the plugin, things are much easier. Just
add the project containing mystuff to the project references.

Also, it should be possible to try out the mutable experiment without
having to use JFit or extra Java code. Here is an example that is
based on using a Java Object array to define a mutable data type:

module Mutable;

import Cal.Core.Prelude using
typeConstructor = Int, JObject;
function = input, intToString, output, seq, toCalValue,
unsafeFromCalValue;
;

import Cal.IO.Console using
function = printLine;
;

//Import Java arrays to provide mutable data
data foreign unsafe import jvm "java.lang.Object[]" JObjectArray;

foreign unsafe import jvm "newArray" newArray :: Int -> JObjectArray;

foreign unsafe import jvm "subscriptArray"
subscriptArray :: JObjectArray -> Int -> JObject;

foreign unsafe import jvm "updateArray"
updateArray :: JObjectArray -> Int -> JObject -> JObject;

example :: Int -> ();
public example start=
let
m = makeMutable (start::Int);
in
printLine ("Now it is " ++ (intToString (getMutable m)))
`seq`
setMutable m (getMutable m + 1)
`seq`
printLine ("But now it is " ++ (intToString (getMutable m)))
;
/**
* Mutable represents a typesafe value that can be changed.
*/
data public Mutable a =
private Mutable value :: !JObjectArray
;

/** make a new mutable variable */
makeMutable :: a -> Mutable a;
public makeMutable value =
let
m = newArray 1;
in
updateArray m 0 (output (toCalValue value)) `seq`
Mutable m
;

/** Put a value into a mutable variable. */
setMutable :: Mutable a -> a -> a;
public setMutable !mutable !value =
updateArray mutable.Mutable.value 0 (output (toCalValue value))
`seq`
value
;

/** get a value from a mutable variable. */
getMutable :: Mutable a -> a;
public getMutable !mutable =
unsafeFromCalValue $ input $ mutable.Mutable.value
`subscriptArray` 0;


Hope this helps,
Magnus.





On Nov 16, 2:06 pm, helmut <helmut.preinin...@chello.at> wrote:
> hi
>
> i want to test the cal <-> java example fromJesper- i make a jar

helmut

unread,
Nov 18, 2007, 5:08:45 AM11/18/07
to CAL Language Discussion
hi Magnus

thanks it helps

i observe a "strange feature", perhaps it is the same as test.x.Var
the package hase.DFrame -> the ICE.bat compiler does't found
the package hase1.DFrame or hase2.DFrame works (hase1 and hase2
without a period)

Helmut

Bozidar Ilic

unread,
Nov 18, 2007, 7:19:23 PM11/18/07
to CAL Language Discussion


On Nov 18, 2:08 am, helmut <helmut.preinin...@chello.at> wrote:
> i observe a "strange feature", perhaps it is the same as test.x.Var
> the package hase.DFrame -> the ICE.bat compiler does't found
> the package hase1.DFrame or hase2.DFrame works (hase1 and hase2
> without a period)

Helmut, are you using the latest release (Open Quark 1.7.1)? This bug
should be fixed in that.

Cheers,
Bo

helmut

unread,
Nov 19, 2007, 7:28:52 AM11/19/07
to CAL Language Discussion
Hi Bo

I used the latest release 1.7.1

It seems, that if the package-name has only 4 letters then ICE cann't
find the classes.

Cheers,
Helmut

nsha...@gmail.com

unread,
Dec 3, 2007, 12:46:05 PM12/3/07
to CAL Language Discussion
As a beginner at FP, I'm not sure if the following is either correct
or good,
but it does seem to work. It is my attempt to understand the Haskell
IO monad,
and create an equivalent in CAL. The principal idea was to write a
typical
read-process-output loop that one sees in most Haskell programs. The
'go'
function at the end is the CAL equivalent of the following Haskell
code:

go n =
if (n == 0) then
return ()
else
do
ch <- getRandomChar ()
putString "ch="
putChar ch
putString " "
go (n - 1)

To run this try something like 'go 10' and you should see 10 random
characters.

I'd be very interested to hear if this is the correct sort of thing.

Nik Shaylor

-----------------------------------------------

/**
* An experemental IO monad.
*/

module IO;

import Cal.Core.Prelude using
typeClass = Outputable;
typeConstructor = Char, Double, Int, String;
function = error, seq;
;
import Cal.Core.Char;
import Cal.Core.String;
import Cal.Core.Functor using
typeClass = Functor;
;
import Cal.Core.Monad using
typeClass = Monad;
function = anonymousBind, bind, return;
;
import Cal.IO.Console;

/**
* The monadic data structure.
*/
data private IO a =
private IO
value :: a
deriving Outputable;

/**
* Functor bindings.
*/
instance Functor (IO) where
map = mapIO;
;

/**
* Functor mapping (not used in this example).
*/
mapIO :: (a -> b) -> IO a -> IO b;
private mapIO mappingFunction !value =
value `bind` (\x -> return $ mappingFunction x)
;

/**
* Monad bindings.
*/
instance Monad (IO) where
bind = bindIO;
anonymousBind = anonymousBindIO;
return = returnIO;
;

/**
* The bind function
*
* @arg leftIO the left hand IO definition.
* @arg rightFtn the right hand function.
* @return the result of evaluating the right hand IO function.
*/
bindIO :: IO a -> (a -> IO b) -> IO b;
private bindIO !leftIO rightFtn = rightFtn leftIO.IO.value;

/**
* The anonymous bind function
*
* @arg leftIO the left hand IO definition.
* @arg rightIO the right hand IO definition.
* @return the result of evaluating the right hand IO function.
*/
anonymousBindIO :: IO a -> IO b -> IO b;
private anonymousBindIO !leftIO rightIO = leftIO `bind` (\x ->
rightIO);

/**
* The return function
*
* @arg value the value to return
* @return the IO that will deliver the result.
*/
returnIO :: a -> IO a;
private returnIO value = IO value;

/**
* Get a random double value.
*
* @return the value.
*/
foreign unsafe import jvm "static method java.lang.Math.random"
private random :: Double;

/**
* Get a random Char value.
*
* @arg ignored an ignored argument that prevents CAF caching.
* @return the value in an IO.
*/
getRandomChar :: () -> IO Char;
private getRandomChar ignored = return $ Char.fromInt $
Prelude.fromDouble $ (random * 256.0);

/**
* Output a string to the console.
*
* @arg str the string.
* @return the Unit value in an IO.
*/
putString :: String -> IO ();
putString !str =
Console.print str `seq`
return ();

/**
* Output a character to the console.
*
* @arg ch the character.
* @return the Unit value in an IO.
*/
putChar :: Char -> IO ();
putChar !ch =
Console.print (String.fromChar ch) `seq`
return ();

/**
* Test routine .that will write out a number of randomly genorated
characters.
*
* @arg n the number of characters to output.
* @return the Unit value in an IO.
*/
go :: Int -> IO ();
go !n =
if (n == 0) then
Console.print "Done\n" `seq`
return ()
else
getRandomChar () `bind` (\ch ->
putString "ch=" `anonymousBind`
putChar ch `anonymousBind`
putString " " `anonymousBind`
go (n - 1)
);

Bozidar Ilic

unread,
Dec 11, 2007, 1:32:49 AM12/11/07
to CAL Language Discussion
Hi Nik,

It looks good to me. There are a few similar experiments in the Open
Quark distribution- you can search for instances of the Monad type
class for this.

Cheers,
Bo

Nik

unread,
Dec 16, 2007, 3:34:30 AM12/16/07
to CAL Language Discussion
Bo, How would you recommend dealing with things like (Int, Int)? I've
seen a several Haskell programs that have a something like:

type Point = (Int, Int)

Clearly one can define Point to be:

data Point = Point value:: !(Int,Int)

but this does lead to more verbose code, and, presumably, adds an
extra level of indirection. In general I really like the way you guys
have avoided over-sugaring CAL. However, I have seen cases in CAL code
where nice type identifiers have been dropped in favor of (Int, Int)
etc. If you take a look at the following little chess program:

http://www.steffen-mazanek.de/blog/2007/02/haskell-chess.html

You will see it has the following type synonyms:

type Square = Maybe Piece
type Board = [[Square]]
type Pos = (Int, Int)
type Move = Board->Board
type Game = [Move]
type State = (PieceColor, Board)

It look like it would be rather cumbersome to make all these data
constructors, but it would be very sad to lose the abstractions.

Nik
Reply all
Reply to author
Forward
0 new messages