Note: ycr2js is currently a standalone program distributed within the Yhc source tree. The usage guidelines below are relevant only for the standalone version. If ycr2js gets integrated in Yhc tighter than now, some or all of the following statements may be no longer applicable and will be updated accordingly.
The ycr2js program along with additional tools is distributed within the Yhc source tree. Download and install Yhc as recommended here and here. Include the
core=1 options on the
scons command line when building Yhc to generate Core for all Haskell library modules. The
ghc executables should be on the PATH after the installation is coplete.
2 Build prerequisites
3 Building and installation on Unix
Change from the toplevel directory of the Yhc source tree to the
src/translator/js directory. Edit the Makefile to reflect your system configuration and execute commands:
All three commands should finish without error.
4 Building and installation on Windows
This currently does not work, but will do once the Scons build system that Yhc uses has been integrated.
5 What is installed
Makefile in the ycr2js directory instructs
make to place all necessary files relatively to the
yhc executable location. After the installation of ycr2js, the directory structure will be as follows (assuming that prefix is the base path of the Yhc installation):
|pgbuild||XHTML Page Building Utility|
|emptyx.html||An Empty XHTML Page template|
The structure shown above represents a "bare" installation essential for ycr2js to function properly. Actual installation may include more files than these.
The base location of Yhc installation will be further on referred as prefix unless otherwise stated.
6 Compiling Haskell into Core
In order to obtain a linked Core file for a Haskell source(s), the Yhc compiler should be run like this:
yhc -includes prefix/lib/haskell \ [-includes other include directories] \ -linkcore Main.hs [other Haskell source files]
Other yhc options may be used as needed, but specifying the
prefix/lib/haskell directory with the
-include option is important. The
-linkcore option instructs Yhc to link all core files generated together, along with library modules used. It is assumed that the user program's main module is named
Main, and its entry point is
main. Type signature of
Main.main does not matter. The linked core will be output as the file
ycr2js Main.yca Main.main >Main.js [2>Main.core]
The converter takes name of the linked Core file as its first command line parameter, and root names as the rest of parameters. The purpose of root names is to specify functions for which another functions they refer to (or, in other words, reachable) will be kept. For example, a module may contain functions like this:
module Main where import UnsafeJS factorial :: Int -> Int factorial 0 = 0 factorial 1 = 1 factorial n | n > 0 = n * (factorial (n - 1)) | n <= 0 = error "Factorial of a negative value" anyStatus :: a -> a anyStatus a = unsafeJS "window.status = exprEval(a).toString(); return a;" str2 = 'a':'c':'d':"abyrvalg" s5 :: String s5 = 'g': s6 :: String s6 = 'd':"" s7 :: String s7 = "ertyu" main = anyStatus (["aaa","bbb",s7 ++ (head s7):(head s6):str2])
It can be easily seen that
Main.main uses (of this module):
and does not use:
s5 just for the reason of size optimization.
It is possible that a script for a Web page contains several parts not linked symbolically, so don't forget what functions are "roots" and specify them all on the command line.
A good example of this is the
Prelude.error function. It is defined in the Standard Prelude as:
error :: String -> a error s = primError s primError :: String -> a primError xs = trace (xs++"\n") (unsafePerformIO (exitWith (ExitFailure (negate 1))))
Prelude.error function is referred to from every
The ycr2js program uses the overlay file,
So, the Standard Overlay module defines
Prelude.error to substitute one from the Prelude:
module StdOverlay where import UnsafeJS -- To substitute Prelude.error global_Prelude'_error :: String -> a global_Prelude'_error a = unsafeJS "alert(a); return undefined;"
which means that in the case of an error, an alert window will appear, and return of an
As an alternative,
8 Building a XHTML page
In order to build a XHTML page ready to be loaded in a Web browser, another program that comes together with ycr2js is to be used:
onload attribute of page body may be changed.
-t command line option is used to specify the path to the empty page template. A sample template (usable in many cases) comes with ycr2js and is located in
-o option specifies where to place the output file. The
-T option specifies the page title to override one stored in the template. The
-e option instructs that the following file name points to a script to be embedded, and the order of embedding is same as the order of appearance of file names on the command line. The
--onload option results in the <body onload="..."> set to the value specified. The latter should be name of a function encoded as follows:
- all alphanumeric characters remain the same
- all other characters are replaced with an underscore followed by character's numeric code
It is important to set the page body 's onload attribute to
The XHTML Web page is written into the file
Main.html and is ready to be loaded into a Web browser.
9 Tools summary
10 All together: A simple Makefile
Here is an example of a simple Makefile containing rules sufficient to compile and build Web pages from Haskell sources. The
yhc executable must be on the PATH.
Cutting and pasting this Makefile, don't forget about proper tabs usage.
#============ Begin Simple Makefile for Standalone ycr2js ============
# Insert names of Web pages to build here. General naming rule: # if the page is built out of a Haskell file Foo.hs which contains # the main function, the Web page file name will be Foo.html
# If Foo.hs imports modules from any location other than current directory, # add more -includes options to this rule.
%.yca: %.hs $(YHC) -includes $(HSJSLIB) -linkcore $<
%.js: %.yca $(YCR2JS) $< $*.main > $@ 2> $*.coreovr
# These two rules generate visual representation of Core. # Include files with names ending with .yc[ra]txt in the list # of `all' dependencies to build these files: .yca and .js files # will be deleted by make in the very end.
%.ycatxt: %.yca $(YHC) -viewcore $< > $@
%.ycrtxt: %.ycr $(YHC) -viewcore $< > $@
# Don't forget that your "root" module Foo must contain the # `main' function. Its type signature does not matter. # Use the indirect reference via funIdx for the page entry point # because functions are now indexed to have shorter names.
%.html: %.js $(PGBUILD) -t $(XMLTMPL) -o $@ -T "$*" -e $(RUNTIME) -e $< \ --onload="exprEval(funIdx['$*.main'])"
#============= End Simple Makefile for Standalone ycr2js =============