fif - An Introduction
Introduction
fif has been granted the first production version as of May. 27, 2018, so this blog post is going to be a light interactive introduction to the language. But first things first, what is fif?
fif is a stack-based scripting language in clojure(script). It is:
- Stack-oriented
- Interpreted
- Easily Extensible
- Simple
- Sandboxed
Let's get like Yoda, shall we!
Interactive-Repl Get
To improve the interactivity of this blog post, I created a interactive fif repl. You can manipulate the code in-place, and the changes will be evaluated instantly, displaying the contents of the main stack and the contents of the standard output while you type.
You can find the code for it here.
As a first example, i'm going to write the famous "Hello World" to standard output
Go ahead and try changing println
to str/upper-case
or try changing "Hello World!" to a different string, and you should see the preceding Main Stack and Standard Output sections change accordingly.
May the Forth be with you
fif takes a lot of its concepts from Forth, which is most notably one of the first stack-oriented programming languages. In order to program in a stack-oriented language, you first need to place values on the stack, and special values, called word definitions manipulate the values that were previously placed on the stack.
fif supports all values defined in the EDN Format Specification, which consists of all clojure data types.
3.14 ;; Floats
:some-keyword ;; Keywords
a-symbol? ;; Symbols
{:a "a" :b "b"} ;; Maps
[1 2] ;; Vectors
(:a :b) ;; Lists
Several symbols have been defined as word definition functions in order to perform operations on stack values. The most common word definitions to learn about are the arithmetic operations.
1 1 -
2 2 *
3 2 /
The arithmetic word operations take two values off the stack, and push the result of those two values back onto the stack.
By chaining these stack operations together, you can use fif as some sort of advanced calculator.
But besides basic arithmetic, fif has a wealth of other word functions at your disposal. If only there was an easy way to learn about them...
Developing through self-discovery
fif has a set of word functions used specifically for self-discovery. I'll be going over each of the more useful ones so that you can begin exploring.
see
see
is probably the most important repl function in fif. To explain what it does, let's see
what see
does...
see
provides information on whatever value comes after it. Go ahead and try replacing see see
with see +
or see pr
to get information on what they are, and what they do.
see-words
see-words
provides a way to get a glimpse at every word definition in the current fif stack machine.
This word definition was taken from Forth, and given the overwhelming amount of information, it makes it difficult to learn anything in particular about fif. Fortunately there are other word operators that are far more useful.
see-groups
If you've already been using see
, you probably noticed that word definitions have an assigned group.
see-groups
lists every group present within the fif stack machine. Note that word definitions that are part of the standard library have groups that are prefixed with stdlib
.
Want to see what words make up a particular group? The next section covers that.
dir
dir
is used to show what word definitions make up a particular group.
The results of dir :stdlib.repl
appears to show variants on see-words
and see-groups
called see-user-words
and see-user-groups
. All of the standard library word definitions are specially defined so that these repl variants can provide information on user-defined word definitions.
Defining New Word Functions
fif allows you to define new word functions. It wouldn't be that useful as a scripting language, otherwise.
;; group add2 :arithmetic
fn add2
2 +
endfn
_ 2 add2
_ see add2
In this example, the word function add2
was created, which simply adds 2 to the top value. More importantly, you can see that it appears as a word function when using the see
word operator.
You'll also note that two lines were left commented at the top of the repl code section. As an exercise, feel free to uncomment these lines to see what effect it has on the output.
Defining New Word Variables
fif has two types of variables at your disposal. Their uses are based on whether you define them in a word function or not.
The first type of variable is a global variable, which is defined statically with def
, and programmatically using setg
def cat-fact-1 "A group of cats is called a clowder."
_ ;; Display our cat fact
cat-fact-1 println
_ ;; Change our cat fact programmatically
*cat-fact-1 "Cat Fact Missing" setg
_ cat-fact-1 println
The second type of variable is a local variable. Local variables are defined statically with let
, and programmatically using setl
.
Local variables are dynamically scoped within function declarations, which makes them a great way to generate function arguments from the stack.
def y "Global Variable Y"
_ doc add "( x y – n ) Add top two values together."
fn add
;; Create locally scoped function arguments
*y swap setl
*x swap setl
_ ;; Function Body
x y +
endfn
_ 1 2 add
_ x println
y println
In the variable examples, a new concept was introduced. Any symbol that includes a pointer symbol, *
, infront of it has the pointer symbol removed, and is placed on the stack without being evaluated. This is refered to as Word Referencing, and it is required in order to define variables programmatically. I would also like to note that Word References can be stacked by preceding the symbol with ever more pointer symbols.
_ x *x **x ******x
_ *x 20 setg
_ x *x **x ******x
Introductory Taste Test Complete
So far, i've covered:
- Using fif for basic arithmetic
- Finding pre-existing word functions and word variables in a fif stack machine.
- Defining new word functions and word variables in a fif stack machine.
- An interesting cat fact
In my next blog post, i'll be covering conditional forms, conditional loops, and the functional operators.
But... I want to know more!
If you would like to learn more about fif, and what it has to offer, the github page goes more in-depth into most of the standard library operators, and also explains how to extend and use fif in your clojure(script) projects.
There is also an online fif playground which contains scripts expressing the many things you can do in fif. I will be covering each of these in later blog posts.
Whale, that's it
If you feel like I've missed something, or you wish to exchange facts, you can find me on the clojurians slack as @benzap.