The world's smartest i/o device for Haskell
Jan Skibinski, Numeric Quest Inc.
Initialized: 2000-11-01, modified: 2000-12-05
I claim that such device exists, that it is available for free and that it is very easy to operate. I will temporarily withhold its real name and give it a pseudonym 'Smarty'. But I will unmask it later, at the bottom of this page. Bear with me please..
As it is now, Smarty prefers Unix operating system as its means of communication with Haskell. But - given some extra work - it will happily serve the Haskell programs on other platforms as well.
Smarty has incredible 2D and 3D morphic graphics and interactive graphic environment, reads and writes many types of graphic files, understands postscript and html, knows all about sockets and internet, has its own web browser, mail user agent, two web servers, and many, many other goodies. It runs on many platforms and many types of computers - including pocket size ones, and is very, very easily portable across all those platforms. Smarty has its own interpreter and supports Foreign Function Interface (FFI), which may make it easy to use it with Haskell.
Simplest possible interface
I will shortly demonstrate how to interface it to Haskell interpreter Classic Hugs - using the simplest means of communication: the exchange of strings. In this model one does not even need FFI at all: the presence of intelligent intepreters on both sides makes it possible to develop a string format translation service, which could be used in any form of sophisticated conversation between Hugs and Smarty. But in this demo I am not even going as far as that; I am just showing how easy it is to query the Hugs modules from within Smarty.
I will start with the invocation of Hugs interpreter from within Smarty:hugs := Hugs on: '/usr/local/bin/hugs'.and from now on I can query the Hugs process, until I get tired of it and quit:hugs quit.A simple example of a Hugs query:hugs answer: 'reverse $ map (*2) [1..5]'gives us this familiar result embedded in a Smarty string:'[10,8,6,4,2]'
This way you can get exactly the same information as you would normally receive during a regular Hugs session. You can type all legal commands, such as ':browse Prelude', ask for type of an expression, or evaluate any legal or illegal Haskell expression. Hugs will happily carry those tasks -- not even being aware of the fact that it is being commanded by Smarty. Things happen this way because Smarty has invoked Hugs as a separate Unix process and intercepted its i/o streams - replacing them by two Unix pipes.
A way to GUI
The results are displayed in one of the Smarty's windows, which looks more or less like a traditional terminal. A very little work (and when I say 'very little' I really mean it) would be required to dress it up in some sort of a two-panel window, add some control buttons and then claim our little victory. As another simple example of GUI consider this little gadget, which we call the Hugs observer:
It uses a traffic lights analogy to provide us with some immediate feedback:
- Red light - Hugs interpreter has been disconnected.
- Yellow light - Hugs is waiting for another command
- Green light - Hugs is computing and data is being collected on the pipe
Most of the time the Hugs computations are so short and fast that the green light flashes very fast and is not even noticeable. As a result you will see only the yellow light. But when computations are lengthy, or non-terminating, as in '[1..]', the green light makes us aware of possible trouble. In this case sending 'break' command to Hugs terminates such computations almost immediately and causes the yellow light to come up again. Such things are possible since Smarty supports multithreading, thus allowing us to run lengthy computations or data collection in a background thread and keeping the GUI responsive and ready for emergencies, such as 'break'.
The observer conveniently displays our requests and the Hugs responses in two separate lines - adjusting its size dynamically. But it truncates the answers if they become too lengthy to display them on a single line. However, the terminal-like capability is still there to examine the full responses. Well, almost full, since we might add as a precautions a safety feature which would truncate any output if its size exceeds certain limit size of our receive buffer.
But this is all besides the point, because we would not gain much from such decorations but some user convenience. A true power of this solution would come with the next step: two way conversation between Hugs and Smarty. This way Hugs could build its own user interface on the fly, or use a one prebuilt in Smarty, to graphically display results of its computations, and reactively respond to user requests from Smarty's GUI. To achieve this level of interaction one would have to supply a Haskell module, which should support something of this sort:request :: String -> IO Stringwhere the result could be then examined and evaluated by Hugs to produce some meaningful data for further monadic computations. But Smarty does not automatically produce Haskell parsable strings, and someone would have to supply a translation service: either Smarty itself or some specialized Haskell module.
But do we really need a one more display device? We already have few good GUI's for Haskell: Fudgets, SOE package, bindings for TK, for Gnome, for Mesa, Clean's Object Library being translated to Haskell, etc. But I suggest that Smarty's morphic GUI beats them all from point of view of sophistication ("Oh no, yet another boring widget") and rapidity of development. Play with it first to appreciate it!
Aren't we all bored with getline monadic examples?
For tutorial reasons a concept of files is often used to explain how the monadic world operates. But files cannot talk back to us and all we can do is to examine their contents or write to them. Smarty, on the other hand, is an intelligent device that can converse with Haskell in many very innovative ways.
Interactive Development Environment
Smarty has very sophisticated development environment which could be patterned upon when designing the one for Haskell. All what is needed is to query some Haskell module for parsed data and let the Smarty do the rest: display it in some nice and useful form and then respond to user requests from within the Smarty's GUI to dynamicly request more data from that specialized Haskell module. Sure, this all can be done in Fudgets or SOE, but before such promisses materialize here is much faster way to achieve the goals. Take a look at a prototype explorer - one of many possible tools for Haskell, which can be easily developed in Smarty.
Here is also a prototype of a more advanced tool, the Haskell Module Browser.
Smarty has a translator from its own language to C. If one needs the services of external C modules one can easily and clearly develop them in Smarty and then ask the translator to produce a directory with .c and .h files - ready to compilation to dynamic loadable modules: DLL on MS platform, *.so on Linux, etc. All you need to do is to move that directory into a proper place of Smarty's source code tree and run: 'make', followed by 'make install'.
As a matter of fact, a module that delivers interface to Unix external processes, and therefore makes it possible to run the demo described above, works this way: when you load it to Smarty it not only installs its high level interface, but also automaticly and magicly creates such ready to go directory with C files. This module is available here, courtesy of David T. Lewis, <email@example.com>. David has designed an abstract interface to any operating system, with many good hooks for concrete implementations, but he implemented only one concrete interface: to Unix/Linux - leaving the room for others to implement the interfaces for other platforms, if needed. This is why I said in the introduction that Smarty prefers Unix for its communication with Haskell.
Since I already started to give some pointers away, here is my own Smarty's code that supplements David's work, and which is designed to work with Classical Hugs, as shown above.
It has been a long time since I last examined Manuel's Haskell->C translator. But if it works as efficiently and effortlessly as the Smarty's translator, then it must be a very good tool.
Foreign Function Interface
Aside from its direct communication with C via plugin modules Smarty also provides a higher level, FFI interface. In theory it could be used to interface with any language, Haskell included. In practice, the Smarty's FFI implementation is C-centric, but - granted that Haskell has also its own C-centric FFI - it should not be too difficult to interface Haskell dicrectly with Smarty. This would open a different ballpark game - much more sophisticated than that previously described.
Other Haskell environments
Everything that was said above applies not only to Hugs, but also to other Haskell environments: HBC, GHC or NHC. Either a simplistic string-based, forever loop with dynamic compilation support would be required, or FFI could be put into a good use to run sophisticated Haskell programs, dynamicly interacting with Smarty. Particularly, hmake could greatly benefit from such easy interactive environment as Smarty.
Time to unveil the Smarty's identity
I guess, majority of you already know what's hidden behind the pseudonym Smarty. Yes, it is Squeak, a freely available Smalltalk language and environment. If you survived my writeup up to this point, there is no reason why you should be put off by the mere name Smalltalk. Go back to the beginning and assess my points again. After all I named it: 'The world's smartest i/o device for Haskell'. I am not ashamed that I know and appreciate Smalltalk: I started with it many years ago, saw many of its shortcomings and came back to it again for many reasons. After all I was recently able to find a paid project to be done in Squeak, while I am still clueless how to find a similarly paid project in Haskell.
Some advice for those who want to try
Squeak is in a flux. There is not even a clear boundary between the versions. Some people work on 2.8 and 2.9 versions at the same time - as of this writing. The stable version is 2.7. But the organization of files in Unix port (and this is what you would need for a start to take advantage of both: David's and mine additions) changes quite frequently due to the standarization process under way. The best shot is to download the 2.8-4 version. Ignore binaries. Ignore rpm's. Ignore 2.9 version, because it is not as well organized yet. Grab the source code of virtual machine and plugin modules, Squeak-2.8pre4.tar.gz, from INRIA site (633 kB), courtesy of long standing porting efforts of Ian Piumarta.
Unfortunately, organization of this directory, as well as similar directories in other mirrors is a bit messy and misleading. So take this advice:
Download Squeak methods in (almost) plain English (this is common for any version above 2):
SqueakV2.sources.gz (1329 Kb) or Squeak-2-source.tar.gz (1331)
Download a tar file which contains an image and a changes files (version 2.8-3 goes just fine with virtual machine 2.8-4):
Squeak-2.8pre3.image.tar.gz (5691 kB)
Download Squeak FFI if you want to play with it. This code is platform specific. For example Linux i386 needs this:
Squeak-ffi-2.8-3.i386.rpm (30 Kb for Linux i386)
Finally, you will need a source for low level libffi library for your platform. Original source code is available at Cygnus Solutions (sourceware.cygnus.com)
How big is it?
Big! The 2.8 image is about 6-7 Mb. But you do not need everything in there. In theory you could remove plenty of classes out of the image and end up with something around 500 Kb. More practically, about 1M if you want to retain morphic graphics (Yes, you would like to keep them!). There are some removal methods ready to use but they are not too refined. Mailing list examples are probably better for this. Trying to explore on your own is too daunting a task if you are not so experienced with Squeak. Problem is that Squeak folks do not think modularly and there are many mutual dependencies all over the place. But they just started appreciating the modularity and there are some projects on the way to handle this problem.