Skip to content

Instantly share code, notes, and snippets.

@robjens
Last active November 8, 2015 15:09
Show Gist options
  • Select an option

  • Save robjens/24789b1127e774ac73e5 to your computer and use it in GitHub Desktop.

Select an option

Save robjens/24789b1127e774ac73e5 to your computer and use it in GitHub Desktop.
Some tips and tricks for Wisp, the homoiconic Clojuresque Lisp for JavaScript in Node and the browser.

Vim (editor)

Personally, I still fall back to plain-old console/println debugging output more often then I’d like. Especially when I’m a bit lukewarm, although in those cases, I tend to use browser based JS, perhaps even the Try Wisp browser editor which instantly compiles to JavaScript (unless you screw up) and helps to get the mind acquainted to the situation and syntax.

While venturing deeper in the language however, you’ll find that for example macro’s cannot be dealt with in the Try Wisp online editor/compiler and one has to move to the local machine instead to experiment further. The REPL, by the way, really isn’t half as useful as it can (and perhaps should) be although some steps have been made to improve on this.

Since I work over SSH quite often, also in hot remote development/test tweaking, I almost always use vim.

Additions to ~/.vimrc

One or two of the things I’ve setup in my custom ~/.vimrc run-command file, actually are enhanced by a few other system utilities and tweaks as well, which I’ve mentioned below:

  1. edit your ~/.zshrc or ~/.bashrc file and add stty -ixon to the foot of the file (Allow for e.g. vim to use ctrl-s to save)

  2. download python and use pip to install pygmentize

Now to ~/.vimrc I’ve added:

" File types
BufRead,BufNewFile *.wisp set filetype=clojure
au BufRead,BufNewFile *.edn set filetype=clojure

" Command runner
au BufEnter * if match( getline(1) , '^\#!') == 0 |
\ execute("let b:interpreter = getline(1)[2:]") |
\endif

" F5 run wisp code in Node.js and executes effects in running process
fun! CallInterpreter()
  if exists("b:interpreter")
    exec ("!".b:interpreter." %")
  endif
endfun
map <F5> :call CallInterpreter()<CR>

" F6 compiles Wisp code to JavaScript and displays result in terminal ANSI color
fun! CallCompiler()
  if exists("b:interpreter")
    exec ("!".b:interpreter." -c --no-map % | pygmentize -l javascript")
  endif
endfun
map <F6> :call CallCompiler()<CR>

Don’t forget to make your wisp source files (I conventionally place them in src/ directory) as executable using (in Vim) !chmod +x % and via terminal chmod +x <filename>. In the case of vim, to catch up on the shebang, a close and reopen of the file may occasionally be needed. The shebang itself would be a typical wisp executable !#/usr/local/bin wisp (one which I’ve patched and recompiled, more later).

Why I mentioned macro’s in the prelude of the prose in the file above this one (1-vim.asciidoc), was actually because it was leading up to a realization which I hadn’t had before, which involves macro’s.

Although wisp macro’s are definitely flawed, in their current implementation, mostly due to the fact that they cannot be exported outside the module (file). There are however, ways around it. Since wisp itself uses a simple Makefile build process, macro’s can easily be inserted to each and every code file needing them using concatenation of file bodies.

But, there are other traits to the macro system, which make them fun as well. And definitely worth while studying if you like to learn some more about both JavaScript, lisp-like macro systems and general comprehension of both languages.

The vim F5 (run compiled code) and F6 (color output compiled js) really help in clearing out the differences in the macro system and exploring some of the potentials it has.

For one, I never knew I could do overloads with the macro’s, which is quite nice as it allows us to create functions in any place by slight variations in the calling parameters to the macro, to produce completely different function identities, bodies and have (potentially) very different effects.

Time to experiment :) Prepare a simple file with perhaps a namespace or two on top. You’ll probably want to reference wisp.ast so be sure to include it both as a global installation (potentially tweaked, compiled and npm linked) and then include a local reference to the package either by remotely pulling (canonical) wisp via npm install wisp or by linking a local (hacked) project which was compiled earlier (npm link from the folder and npm link wisp in the local project root folder)

Note
Keep in mind, if you wish to quote/unquote/splice quotes you may run into the namespace reference problem where suddenly your (list foo bar baz) may not work anymore. The suitable solution is to make the namespace explicit e.g. (wisp.list foo bar baz) (or (wisp/list …​) which is equivallent)
(ns example.foo
  "File is presumed to be in the `example/` folder named `foo.wisp`"
  (:require [wisp.ast :refer [symbol]]
            [wisp.sequence :refer [list]]))

Some unexpected things, try:

(defmacro → [& operations] (map rest operations))

;e.g (-> (vec [1 2 3]) (first) (second) (map fn))
[[1 2 3], list(), list(), fn()]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment