
By Dan Shafer
MacTech Quarterly
Spring 1989 — Page 50
In the past several weeks, I have become aware of several meta-language extensions to HyperTalk that seem to suggest some interesting ways in which Our Favorite Language might be used in the future. I developed one of them for use in a specific project, another came to my attention on CompuServe and a third was sent to me by a reader of my book HyperTalk Programming to show me what could be accomplished by a relative programming neophyte.
While these programs differ from one another in purpose and scope, they have in common one thread: the use of HyperTalk to create HyperTalk code and/or HyperCard stacks. In this column, I want to take a specific look at each of these tools. But first, let’s explore the issue of a meta-language.
Meta-What?
Just after my program, Dan Shafer’s scriptExpert, made its debut, I was addressing a meeting of the Berkeley Macintosh Users Group. As I explained what I had tried to do in building the program, one of the audience, a bright engineering guy, said, “Oh, so what you’ve done is build a meta-interpreter for HyperTalk entirely in HyperTalk.” I paused. “If you say so,” I answered. The response got a lot of laughs, but the fact is that I didn’t set out to write a meta-anything. I have since, however, become more aware of the importance of meta-tools in many aspects of things in which I have a deep interest, including HyperTalk.
The idea of a meta-language is not entirely new and it’s clearly not confined to HyperTalk. Languages like LISP and Prolog, for example, have often been used to create language parsers or interpreters that could create another interpreter for a language whose rules and behavior were specified in some format other than a programming language. The idea is fairly simple. Start with a file that contains some kind of description of what you want a program to do and how you want it to behave. Then write a program in the target language to read that file and generate the appropriate programming code to produce the desired result.
There are several major advantages of such an approach to language use. Two are significant for us.
First, the more free-form and English-like we can make the rules about how to construct the text file from which the program generates the code, the more accessible we make the language. People who would have a great deal of difficulty writing usable Prolog code, for example, find it easy to write the specifications for a new language grammar in a form that a Prolog program can read and create appropriate Prolog code to handle.
Second, it is quite often possible to transfer programs and files around among users in a much more efficient way as meta-files containing descriptions of finished results than to send the finished results themselves. This leads to a corollary advantage: things that can’t be described precisely enough in words and pictures can be reduced to relatively small fragments of descriptive text. In the case of HyperCard, this may turn out to be a far more significant advantage than is yet obvious.
A meta-language, then, can be thought of as a language that is about a language.
Creating an Expert System
The first meta-language tool I want to describe is one I built. My HyperCard software publisher, Hyperpress Publishing of Foster City, CA, publishes an expert system shell product called Intelligent Developer. This shell provides a framework within which subject-matter experts like engineers, lawyers, and architects can write rule-based expert systems for Macintosh delivery. I helped place the shell with Hyperpress and have written some of the documentation for it.
As the product was moving toward publication, Publisher David Gewirtz, an avid HyperCard fanatic, kept wondering out loud if we couldn’t find a way to deliver finished expert systems in HyperCard rather than in the Intelligent Developer’s own environment. After a number of discussions, we decided to give it a try.
The result is a product that is included with each copy of Intelligent Developer. It’s called IntelliCard™ and it makes it possible for expert system developers to deliver their entire finished product in HyperCard.
Key to building IntelliCard was the need to be able to extract from an Intelligent Developer knowledge base (i.e., document) all of the rules, facts, graphics, and other elements that make up an expert system from the user’s viewpoint. Then we had to put those elements into the HyperCard stack. Well, extracting the components of the knowledge base turned out to be a relatively difficult task but C programmer extraordinaire Dennis Chan proved more than equal to the task. As he designed that phase of IntelliCard, though, it became clear that we would have to transfer the information from Intelligent Developer to IntelliCard in two pieces. First, all of the rules and facts that would be invisible to the user of the stack would have to be protected against alteration. We decided to stuff them into the Resource Fork of the IntelliCard stack. This is also where the inference engine code (the “brains” behind the expert system) resides. But that left us with all of the elements of an expert system that the user sees during consultation with the finished product and that the designer might want to change once he got it into HyperCard. These elements included questions to be asked of the user, output screens for displaying intermediate and final conclusions, explanatory screens to display when the user asked how a conclusion was reached or why a question was being asked, and notices to the user about the status of the consultation.
Each of these elements clearly required a card in a stack. We decided to write a series of handlers to deal with this problem. Chan’s routines placed a knowledge base’s unchangeable information into the resource fork of the destination stack and the user-directed pieces into a text file in a format we agreed upon. My HyperTalk scripts — later augmented by some fine work of Chan’s as the project evolved — dealt with the intermediate text file. It read through that file and created copies of pre-designed prototype cards for each type of question that could be asked (single-answer, multiple-choice, free-form text entry, etc.). It actually created a new HyperCard stack by copying cards from an existing one, adding knowledge-specific content to each card as it was copied, and ending up with a stack that was for all practical purposes a finished, deliverable expert system.
The scripts that carry out this construction are far too large and numerous to reproduce here, but it may be instructive to look at one example. The script in Listing 1 is part of the IntelliCard stack-generating code. It creates radio buttons on a card once it has been established elsewhere that the type of question being posed to the user and the nature of the answer expected dictates that a radio button set is the right way to approach the problem. The approach to the problem in the makeRadioButtons script follows the pattern of the other handlers in the stack-creating scripts.
Item 8 of the global variable called factRec is placed there during knowledge base extraction. It tells this script how many radio buttons need to be created for this question. (Actually, factRec is used repeatedly to hold the current line of the intermediate text file while we work with the facts in that file. Item 8 of a fact that has already been determined to be a single-answer multiple-choice type of fact tells me how many alternative answers there are.)
Having created a copy of the appropriate prototype card, we simply set up a loop in which each button is created, given appropriate attributes (style, text and name) and then placed near the bottom of the card. The handler that manages placement of the buttons is placeButton and it appears in Listing 2. It uses a fairly simple algorithm to place each button (to a maximum of 20 buttons) on the card so that they are evenly spaced horizontally and vertically into the area allotted to buttons in each of the prototypical card designs.
The important thing about this approach is that we’ve been able to start with a text file that has no knowledge of HyperCard and arguably includes nothing that is HyperCard-specific and create cards in a HyperCard stack by means of a program written in HyperTalk. This means that we could design an IntelliCard interface for any other expert system shell so long as we could produce an intermediate file in the appropriate format for these HyperTalk scripts to read and use as instructions to build a HyperCard stack.
Going the Other Way
Scott Neufeld has created a stack called GENESIS, a shareware product for which he asks a fee of $15, to translate a HyperCard stack into an intermediate text file format he cleverly calls a “DNA” file. (Wish I’d thought of that!) His stack can also read such DNA files and generate a HyperCard stack from the text description.
In Version 0.50, GENESIS deals only with fairly simple stacks. It does not, for example, deal with XCMDs and XFCNs. Graphics are also not yet supported, though Scott promises that a future release of the product will do so. As he says in the stack itself, it deals only with:
- Scripts of card & bkgnd buttons, card & bkgnd fields, backgrounds, cards, and stacks.
- All the attributes of buttons and fields.
Still, the approach is instructive. It was inspired, Scott tells us in an introduction, by his reading of Macintosh magazines and their attempts to describe to readers how to construct a particular card. (“Put a round-rectangle button just a little below and to the left of the center of the card.”) He wondered if it wouldn’t be possible to come up with a standard way of describing a HyperCard stack in pure text so that a magazine could print a listing of such a stack and users could use a stack like GENESIS to read the text file and create the stack exactly as intended. Not a bad idea, I’d say.
GENESIS produces a separate entry in a DNA text file for each component in a stack. Field contents, scripts of fields and buttons, and descriptions of fields and buttons are all included. Listing 3 shows a sample of what a DNA entry for a button might look like. Lines 2 and 3 describe the button’s name (opencover), location (0,9,253,331), style (shadow), showName (true), autoHilite (false), icon number (0, meaning none), type face for the button’s name (Chicago), alignment of that text (center), size of the type (12 points), and the style of that text (plain).
Following the description of the button, the button’s script is reproduced. (For fields, their contents and their scripts are listed in the DNA file.)
The key word *SCRIPTEND tells GENESIS that it has reached the end of this object’s definition. Another key word, *ENDCONTENT, tells the stack when to move to the next card in the stack.
GENESIS comes with a small sample address stack in the form of a DNA file. You can re-create the stack from the text file. GENESIS even includes an option that lets you watch the stack-building process. That slows things down a good bit, but the first few times, it’s fun to watch stacks take shape before your very eyes!
Generating Artwork
A third approach to the HyperCard meta-tools business is the work of Dr. Jane Miller of Lasalle, Quebec. She sent me a copy of her stack PURR-Draw. (She is evidently a cat lover, but I decided to write about her stack anyway!)
PURR-Draw enables you to click on the corners of a drawing you paste into the stack, and then have the stack build a script to recreate the drawing in HyperTalk. It is like a dot-to-dot in reverse. Like its coloring-book counterpart, it’s limited to straight lines between the dots you point to, but you can still create some fairly nice effects.
It may not be entirely clear why you’d want to write a HyperTalk script to create a drawing when it would be as easy to paste the real drawing into the stack and be done with it. But, like GENESIS, PURR-Draw could be used as a way of conveying in printed form the contents of a drawing you wanted someone else to include in a stack you were having them build.
PURR-Draw and GENESIS are both outstanding seminal products. They both have room for lots of growth and will undoubtedly be extended by both their authors and other users who see ways to improve upon and extend the
ideas embodied in these early versions of promising HyperTalk tools.
Listing 1
on makeRadioButtons
— © 1988, Dan Shafer and Hyperpress Publishing
— All rights reserved
— Do not reproduce or use in any form without
— express prior written consent of copyright
holders.
global factRec
put item 8 of factRec into numItems
put numItems into field “numOfAnswers”
put 8+numItems into loopNum
repeat with counter = 9 to loopNum
doMenu “New Button”
choose browse tool
set style of cd btn “New Button” to radiobutton
set the textFont of cd btn “New Button” ¬
to “Geneva”
set the textSize of cd btn “New Button” to 9
put item counter of factRec into btnName
set the name of cd btn “New Button” ¬
to btnName
placeButton counter
end repeat
end makeRadioButtons
Listing 2
on placeButton number
put number-8 into kounter
put kounter/4 into column
put 15*(kounter mod 4) into pos1
if pos1=0 then put 60 into pos1
if column≤1 then
set the rect of cd btn kounter to 0,(270+pos1),100,(285+pos1)
choose browse tool
exit placeButton
end if
if column≤2 then
set the rect of cd btn kounter to 100,(270+pos1),200,(285+pos1)
choose browse tool
exit placeButton
end if
if column≤3 then
set the rect of cd btn kounter to 200,(270+pos1),300,(285+pos1)
choose browse tool
exit placeButton
end if
if column≤4 then
set the rect of cd btn kounter to 300,(270+pos1),400,(285+pos1)
choose browse tool
exit placeButton
end if
if column>4 then
play “boing”
answer “Too many buttons for fact” && item 1¬
of cd fld 1 with “Abort” or “Proceed”
if it is “Abort” then exit to HyperCard
end if
end placeButton
Listing 3
opencover,0,9,253,331,shadow,true,false,0
Chicago,center,12,plain
on mouseUp
set lockscreen to true
hide me
hide bkgnd button “address”
hide bkgnd button “phone”
hide bkgnd button “help”
hide bkgnd button “cover”
hide bkgnd button “x”
hide bkgnd field “address”
hide bkgnd button “new”
hide bkgnd button “goleft”
hide bkgnd button “goright”
hide bkgnd button “search”
hide bkgnd field “stackname”
set lockscreen to false
end mouseUp
*SCRIPTEND