TABLE OF CONTENTS
Set Up a Dev Environment for Writing or Integrating Custom Libraries
Open a Terminal Session in the Working Directory
Update/modify your init.ss file
Functions You Wish To Make Immediately Available
Add Library Code to Your \lib Directory
Add Scripts to Your \scripts Directory and Run Them
Set Up a Dev Environment for Writing or Integrating Custom Libraries
Aside from defining lambdas in your workbooks, you also have the option of making Scheme library code available for use in all of your workbooks, even if the workbooks themselves are stored, for example, on OneDrive or SharePoint. This can be code you write, or code you install from trusted commercial or open sources. Because Scheme code is text-based, integration with source control technology is a breeze.
Towards this end, AcceλerateTM for Microsoft 365 provides a “working directory,” located at C:\Users\<your-windows-username>\.accelerate. This is where you configure and customize your installation to take advantage of code reuse outside the confines of a single workbook. The working directory gets created automatically on first use of the add-in, and is populated with a few boilerplate “starter files,” which you can modify as you see fit.
Should you ever want (or need) to return to this “original state,” just back up the .accelerate directory by renaming it to something else (e.g., .accelerate_bak), and the next time you open Excel, the “original” boilerplate files will be restored to .accelerate.
We provide access to this working directory from the Ribbon menu. You can open either a terminal session in the working directory, or a REPL session in adb.exe, our command line script runner.
Unlike the REPL built into Excel, the adb.exe REPL works in its own process, outside Excel. This has advantages and disadvantages, depending on what you are trying to do—which is why we provide both options.
The advantage of operating in a separate process is that nothing you can do in that session can cause Excel to crash. Life in the REPL can involve errors, exceptions and even crashes, and that’s a normal part of working in the bottom-up fashion associated with REPL-based development. The disadvantage is that you have access to none of the objects in your currently running Excel instance available for automation purposes without writing some advanced code. It’s doable, but not easily. From inside the REPL in Excel, you can transpose these advantages and disadvantages: anything you do in it can crash Excel, but you have immediate access to everything happening in your currently running instance of Excel.
Open adb.exe REPL Directly
To run an instance of the adb.exe REPL, just click on the REPL button and choose Open ADB REPL in Windows Terminal:
This will pop up the AcceλerateDB application in “REPL” mode:
This will have loaded your init.ss file and configured your Scheme environment in a way that is identical to the environment you find yourself in after Excel starts up. In order to take control over that environment, you need to update your init.ss file, a process we describe below.
Open a Terminal Session in the Working Directory
To open a Windows Terminal session in your working directory, just click the REPL button, and choose Open Windows Terminal:
This will pop up a PowerShell window in Windows Terminal:
The purpose of opening the Terminal from the Ribbon is to be already located in the Acceλerate working directory, from which vantage point you can open your favorite editor and/or optionally enter the adb.exe REPL manually, by typing ‘adb repl’ from the command prompt.
This has the advantage that it’s easy to enter and exit an adb.exe REPL session, and to fire up your favorite code editor. Popular choices include VisualStudio Code, Sublime Text, Atom, Emacs and even Vi/Vim for Windows. Each will have support for Scheme coding at some level, and we cannot recommend one over another.
Note! Windows Terminal is included by default in Windows 11. If you use Windows 10, you’ll need to install it (for free) from the Windows Store.
Essentially, your “development environment” is already set for you. You just need to know:
What you can do, and
What you want to do.
In terms of what you can do, here are the key possibilities at this time:
Update/modify your init.ss file.
Add library code to your \lib directory.
Add scripts to your \scripts directory, and run them.
Over time we will be expanding that list to include creating local databases and starting up web servers, and much, much more. But for now, we are focusing on basic tasks.
Update/modify your init.ss file
The init.ss file is loaded by VSA® on startup and should contain the following 3 “sections”:
The import spec section.
Any adjustments to the search path you wish to make.
Any custom functions to which you want immediate access, but are perhaps not prepared to package in a particular library structure yet.
If you followed along with our primary tutorial, you are already familiar with this process to a degree. What you need to understand is exactly what you can and cannot achieve with the init.ss script.
Because init.ss is what Scheme considers a “top-level” script, it is expected to load libraries using the (import …) statement at the top of the file. Strict R6RS Schemes require at least one such spec, i.e., (import (rnrs)), but VSA will allow you to omit this and load several libraries by default for you. These are:
Note! We will explain some of these libraries further in subsequent sections about interacting with IronScheme and the CLR.
If you do not omit the (import …) section, then it must be the very first clause in your init.ss file. If you further wish to amend the search path, note that you cannot do this before the import statement required at the top of the file, nor can you run an import statement against that new search path after you modify it in the init.ss file.
The init.ss file really is intended to be run “first,” even before you run a script that you invoke at the command line. Any such script you invoke after init.ss runs can, however, refer to libraries in your modified search path. You can consider init.ss to be “injected” before even the script you want to run, precisely so that anything you add to the search path is accessible to your scripts.
Note, however, that for this to work correctly, you must be running in the working directory. If you run adb.exe outside that directory, you may get unexpected behavior. Adb.exe will load any init.ss file it finds in whatever directory it finds itself. So it is important to work primarily from the working directory Acceλerate expects you to be working in for most purposes. Only work outside that directory when it is intentional to do so.
Amending your Search Path
The Search Path in AcceλerateTM is composed in a very precise way, to preserve a certain precedence for paths to ensure that searches are conducted in a manner in which is most beneficial. The order in which you will want your files searched need to be organized are as follows:
First to be searched: current working directory libraries.
Second to be searched: user- added libraries.
Third to be searched: system libraries.
Let’s say the system libraries provide a library called \foo\bar.sls. Unless a directory with a library matching that path is found in a local or user-defined search path, that’s the “version” of the library that will be loaded. If, however, you add a directory that also matches \foo\bar.sls to the search path, or add it to your working directory’s lib folder, then that will be the “version” of the (foo bar) library loaded. In other words, it will load the library that matches first, in order to give you the ability to “override” downstream versions of libraries with your own should you need or want to provide alternate implementations.
We have provided a function to ensure any user-defined search paths occur in the right order of precedence.
(add-path-to-user-search-path "C:\\path\\to\\custom\\lib\\directory")
This will make sure it does not have precedence over locally defined libraries, but does have precedence over system-defined libraries, should there be a name conflict at import time.
Functions You Wish To Make Immediately Available
Finally you can add functions that you wish to be made immediately available without loading a specific library to your init.ss file. Our tutorial explains doing this, so if you haven’t consulted that yet, you’ll find the details there.
Add Library Code to Your \lib Directory
One of the main purposes of working like this is to add code you wish to refer to in your workbooks to a default library location, which is the “\lib” subdirectory of the working directory.
The version of Scheme supported by VSA® is R6RS, and the entire specification can be found here: http://www.r6rs.org/.
The first thing to grasp about this fact is that the entire R6RS spec is now available to you from within Excel!
Important! The only known limitation of VSA’s underlying IronScheme engine is that there is only basic support for “continuations,” because the .NET Runtime does not support the concept fully. Most of the simple examples of continuations in the R6RS specification work, but not all. Continuations are a very advanced feature of traditional Scheme that you will likely never need in an Excel or Office 365 context. They are used mainly by developers of new programming languages who happen to be implementing them in Scheme for very low-level control over code flow in scenarios only language designers typically face. Therefore, continuations outside of their lexical context cannot be referred to, nor can you implement what are called “delimited continuations.”
What does this mean? Well it means everything, except for advanced examples of using continuations, in the book The Scheme Programming Language, Fourth Edition, by R.K. Dybvig (The MIT Press, 2009) is accessible with the correct (import… ) incantation. Here is the link to this fantastic resource:
In particular, all the “forms” at your disposal from just the “out of the box” Scheme side of things are documented in that book, and referenceable from the following index:
https://scheme.com/tspl4/summary.html#./summary:h0
Inasmuch as VSA is built on IronScheme and IronScheme is a R6RS-compliant Scheme, any deviance from examples in that book should be brought to our attention as possible bugs, keeping in mind that some aspects of the specification give implementers some leeway in interpreting the meaning of the specification. We will gladly review any issue you may find with respect to VSA’s compliance with the specification.
We did not include a separate “Language Guide” in our documentation because basically - that’s it! Between the R6RS specification itself and that book getting into the details of each library that is part of the specification implemented by any “reference R6RS compliant Scheme,” you have a lot of functionality to explore.
In addition to the R6RS specification, IronScheme (and by extension, VSA) supports a number of what are called “SRFI”’s, or “Scheme Requests for Implementation.” There are a couple hundred of these at various stages of acceptance/rejection by the broader Scheme community, but IronScheme includes dozens of these implementations.
The section, “Calling Into IronScheme,” set forth below, will list these and describe several other useful, time-proven Scheme libraries that are included.
If you wish to write your own library, the convention is as follows:
Libraries are contained in subdirectories off the \lib directory.
Libraries traditionally end with a *.sls file extension.
Libraries can import other libraries, and export select forms from imported libraries, as well as forms implemented in the file containing their definition.
Libraries are referred to in import sections of scripts and other libraries based on their physical layout on the harddrive.
The following is a concrete example of writing a library of string utils in a larger library named “my-lib.” You would implement the following structure under the \lib subdirectory of your working directory:
<working directory>:.
├───lib
│ my-lib.sls
│
└───my-lib
str-utils.sls
That is, there would be a file called mylib.sls in the \lib directory itself, a subdirectory of the same name (mylib), and another sls file for the string utilities you plan to expose.
The mylib.sls is intended to be an easy way to load multiple sub-libraries within the mylib space, and would likely directly expose at least one of the string utilities you export from str-utils.sls. This way of providing default exports from top-level library imports is common in Scheme.
The mylib.sls might look like this:
(library (my-lib) ;; name of the library (export str-split) ;; exports (import (rnrs) (my-lib str-utils))) ;; imports
In this case, by importing just mylib into your script, the str-split function exported by str-utils is available. To get all of the functions exported by str-utils, you would import the full (mylib str-utils) library in your import statement. It might be defined with many such useful functions in the str-utils.sls file off the mylib subdirectory:
(library (my-lib str-utils) (export str-split to-upper to-lower kabob-case ;; even more functions ... ) (import ...) (define (str-split s d) ;; more code ... ) ;; ... even more code... ))
By following these conventions, you can create fairly sophisticated and quite large libraries of code that provide consumers of your library - you and anyone with whom you decide to share the library - with nice defaults for importing your code that can be refined and augmented as deemed necessary for their own purposes.
To be clear, the following import statement:
(import (mylib str-utils) ...)
will look for
lib\mylib\str-utils.sls
in every directory included in your search path until it finds the first match. As mentioned earlier, every directory in your search path that has a \lib directory will be examined, in the order you define your search path, so be sure to give some thought to how you order that search path.
Add Scripts to Your \scripts Directory and Run Them
Another thing you will want to do at some point is write one executable script for batch processing or perhaps user interaction.
Scheme calls these “top-level” programs. Top-level programs in Scheme are all expected to start with an (import …) clause. After that you can do anything you want them to do, based on the actual libraries you imported.
A “top-level” program thus has the following basic structure:
(import (rnrs)) ;; import specification - i.e., what libraries to load ;; one or more lines of code doing something (display "Hello, World!") (newline)
In fact, a script that looks just like that except for the comments can be found in your working directory’s \scripts subfolder called, of course, hello-world.scm. You run it as follows:
adb run .\scripts\hello-world.scm
You should see something like this:
If you would like to run it from inside Excel, you call it a little differently in the Excel REPL that Acceλerate for Microsoft 365 provides:
(load "scripts\\hello-world.scm")
And then hit CTRL-Shift-T to test it:
In general, if you expect your scripts to execute unattended for a short period of time it is okay to run from the Excel REPL using the (load …) form. However, if you expect user interaction and possibly long-running processes, then it is NOT recommended to use the Excel REPL to run them, because it could block the main Excel user interface for as long as the script runs. In that case, it’s better to run as a top-level program by calling it through adb.exe as depicted above.
Future versions of Acceλerate will allow for better asynchronous execution of external scripts, but for now follow this rule of thumb. It’s also why we provide adb.exe at the command line, so you have a way to run long-running scripts outside of Excel when that is what you need.
The following terms are registered trademarks of the Microsoft group of companies and are used in accordance with Microsoft’s Trade and Brand Guidelines: Microsoft, Microsoft 365, Microsoft Office, Microsoft Excel, Microsoft Edge, Microsoft Edge WebView2, Microsoft Windows, Excel, Office 365
The following terms are registered trademarks of Apex Data Solutions: Visual Scheme, VSA.
Copyright © 2022. Apex Data Solutions, LLC. All Rights Reserved.