peforth supports jupyter notebook magic command %f
since v1.15 (released to Pypi on 2018.3.12) with both line magic and cell magic.
If you are running this jupyter notebook page online through mybinder.org then no installation is needed.
If you would like to work on your computer, so you can save changes you made, then
pip install peforth
to install peforth and that's all, assume you already have jupyter notebook installed.
import peforth
reDef unknown
Here after, in any python code cell, a %f
leading line is interpreted as a FORTH line, called line magic. The next cell is an example of the version
command that shows peforth greeting message and leaves the version number on the data stack.
%f version .s
p e f o r t h v1.23 source code http://github.com/hcchengithub/peforth Type 'peforth.ok()' to enter forth interpreter, 'exit' to come back. 0: 1.23 (<class 'str'>)
%f ." Hello World!" cr
Hello World!
The amazing thing here is that the %f
line magic can be used in python code. . .
# use %f line magic in a python code function definition,
def hi():
%f ." Hello World!" cr
# believe it or not, it works!
hi()
Hello World!
Now use peforth command .source
to find out why this is possible . . .
%f __main__ :> hi .source
def hi(): get_ipython().run_line_magic('f', '." Hello World!" cr')
The %f
line magic is compiled into a python statement, that's why. Some more explanations given at the end of this page.
%%f
cell magic¶A cell leading with a %%f
(double %%
instead of single %
in line magic form) becomes a block of FORTH code.
%%f Nothing allowed before %%f except white spaces; everything in this line after %%f is ignored.
\ Demonstrating the peforth interpret mode [for]..[next] loop
5 [for] t@ . space [next] cr
\ For experienced FORTH users
\ Where t@ is like the FORTH word r@ but it fetches TIB stack instead of the traditional
\ FORTH return stack. Because TIB is the only resource that belongs to this interpreting
\ life cycle alone.
5 4 3 2 1
Now use the [for]
loop to print a pyramid:
%%f
: star ." *" ;
: 2stars star star ;
: stars for star next ;
star cr 2stars cr 10 [for] 13 t@ - stars cr [next]
* ** *** **** ***** ****** ******* ******** ********* ********** *********** ************
Peforth and the Jupyter Notebook are of different name spaces, meaning that peforth can't see the x
variable in the example below:
x = 123
%f x . cr
123
The reason why we choose FORTH is for its super flexibility. Now let's redefine the way peforth handles an unknown token, i.e. the x
of the above example. Instead of alerting "Error! x unknown."
we let it try to find the token in the Jupyter Notebook __main__
module object.
Note: peforth v1.16 and newer version is required to play this trick. Since v1.23 the 'unknown' introduced below has become a built-in so we don't need the re-definition. Instead, use marker command '===' to forget it so the 'x' would be an 'unknown' again.
%%f Now we redefine the 'unknown' command (it does nothing by default)
: unknown // ( token -- thing y|n) Try to find the unknown token in __main__
py> getattr(sys.modules['__main__'],pop(),"Ûnknôwn")
py> str(tos())=="Ûnknôwn" if drop false else true then ;
\ here after, when FORTH come accross an unknown token, instead of printing the
\ error message, it try to find the token in python __main__ module name space.
reDef unknown
now test again:
y = 'abc'
%f y . cr
%f x . cr
abc 123
peforth seems know the 'x' and 'y' now while it doesn't. This trick is vary useful when we are studying and we can investigate things in FORTH way.
peforth.ok()
is the peforth interpreter itself. Run peforth.ok()
to shell a level of the FORTH interpreter and exit
command to come back.
# Run this cell to enter peforth console (REPL loop or command line interface)
# Note the Out[ ] of this cell, the `[*]` indicates that the command line interface
# is running. Play with it or copy-paste this line:
# "star cr 2stars cr 10 [for] 13 t@ - stars cr [next] exit"
# to try again the pyramid example above. 'exit' command to terminate.
peforth.ok()
star cr 2stars cr 10 [for] 13 t@ - stars cr [next] exit * ** *** **** ***** ****** ******* ******** ********* ********** *********** ************ OK
<module 'peforth.projectk' from 'c:\\users\\hcche\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\peforth\\projectk.py'>
%f
and %%f
magics are actually performing the peforth.dictate('command lines')
exported function, while peforth.ok()
is the REPL loop of the same function. Try:
peforth.dictate(" .' hello world!' cr ")
that works exactly as we have tried at first.
peforth.dictate(" .' hello world!' cr ") # Note the Out[ ] of this cell
hello world!
<module 'peforth.projectk' from 'c:\\users\\hcche\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\peforth\\projectk.py'>
Observed from the above outputs, peforth.ok()
and peforth.dictate()
both return the peforth module object. This means that we can cascade these functions. The next example sees the type of the 'star' command that we definded above:
%%f
' star \ get the word object, we defined 'star' above remember?
:> type \ get 'type' attribute of the word object
. cr \ show what we have got ... it is a 'colon' word, isn't it?
colon
It's correctly a 'colon' word. The next example in python code is actually doing the same thing as the above FORTH code:
# Example of cascaded functions, to check a given FORTH word's type
type_of_star = peforth.push('star').dictate("(') :> type").pop() # cascaded functions
print(type_of_star)
colon
Where (')
and :>
are peforth words explained by help
command as shown below. Function cascading is very useful for peforth to debug or to investigate your python target code.
Peforth functions that can be called cascadedly are: peforth.ok()
, peforth.dictate()
, peforth.push()
and peforth.execute()
.
%f help (')
( "name" -- Word ) name>Word like tick but the name is from TOS.
%f help :>
( obj <sub-statement> -- value ) Simplified form of "obj py> pop().foo.bar" w/return value down to the next whitespace
More information about peforth are on the wiki of the project on Github.
May the FORTH be with you!
H.C. Chen @ FigTaiwan
Last Edited: 2018.6.27
Optionally if you want ipython to load %f
magic automatically at startup of every jupyter notebook, so you don't need to import peforth
explicitly everytime, what you need to do is to make . . .
this config file:
C:\Users\<your user name>\.ipython\profile_default\ipython_config.py (for Windows)
or
~/.ipython/profile_default/ipython_config.py (for Linux)
this line:
# A list of dotted module names of IPython extensions to load.
c.InteractiveShellApp.extensions = ['peforth']
to have 'peforth' in the list as shown above.
__main__
is a peforth word that returns the main program module object which in the current case is this jupyter notebook. __main__
is the parent module of the funcion hi()
and __main__ :> hi
is the way peforth gets the hi
function object. Finally .source
displays the source code on top of the FORTH data stack which is now the hi
function object. So this line magic:
%f __main__ :> hi cr
is compiled to:
get_ipython().run_line_magic('f', '." Hello World!" cr')
Where 'f'
is apparently the peforth magic command's name.