Common Lisp equivalent to Haskell's main function? - scripting

Haskell's main function does just what I want: evaluate when the file is loaded by itself (e.g. ./myfile.hs or runhaskell myfile.hs) and in no other case. main will not be called when the file is imported by another file. newLISP also has this functionality.
Is there equivalent code for Common Lisp?
I read the source code for CLISP. Here's what happens when the user enters clisp myfile.lisp or ./myfile.lisp:
CLISP saves myfile.lisp as p->argv_execute_file.
CLISP creates the expression (LOAD "p->argv_execute_file") and pushes it onto the Lisp stack.
CLISP saves any additional command-line arguments in a list.
CLISP stores the arguments in the Lisp variable *args*.
CLISP never makes a Lisp variable referring to p->argv_execute_file, so there is no way to discern whether myfile.lisp was loaded directly, by the user in the REPL, or by another Lisp file. If only (car *args*) were myfile.lisp, my task would be easy.
Note: Shebangs give CLISP trouble if the file is loaded from the REPL, so I put this code in ~/.clisprc.lisp:
(set-dispatch-macro-character #\# #\!
(lambda (stream character n)
(declare (ignore character n))
(read-line stream nil nil t)
nil))

I found a solution. It's a bit of shell trickery, but it works. I'll soon modify this to work on CL implementations other than CLISP.
#!/bin/sh
#|
exec clisp -q -q $0 $0 ${1+"$#"}
exit
|#
;;; Usage: ./scriptedmain.lisp
(defun main (args)
(format t "Hello World!~%")
(quit))
;;; With help from Francois-Rene Rideau
;;; http://tinyurl.com/cli-args
(let ((args
#+clisp ext:*args*
#+sbcl sb-ext:*posix-argv*
#+clozure (ccl::command-line-arguments)
#+gcl si:*command-args*
#+ecl (loop for i from 0 below (si:argc) collect (si:argv i))
#+cmu extensions:*command-line-strings*
#+allegro (sys:command-line-arguments)
#+lispworks sys:*line-arguments-list*
))
(if (member (pathname-name *load-truename*)
args
:test #'(lambda (x y) (search x y :test #'equalp)))
(main args)))

(eval-when (situation*) ...)
Update sorry for the confusing answer.
I could be wrong, but it seems to be impossible to do what you want exactly. I would make a shell script and call clisp -i myfile.lisp -x (main).
Is there any reason to not make it executable (described here)?
P.S. Common Lisp is a language and clisp is one of the implementations.

Related

Is there any way to take at first the arguments and at last the name in a function in racket?

I was asked to write a program in racket in order to change the behaviours of arithmetic operators from prefix to postfix. More precisely:
I want this code: (a b +) to behave like: (+ a b)
I wanted to use define-syntax-rule in order to change the behaviour of the + operator, but I have one problem, while using define-syntax-rule we write at first the name of our macro, and after that we write the arguments.
My question: Is there any way to write the arguments at the beginning and the name at last in racket functions?
The easiest way to accomplish this is to create your own #%app macro. Since you are essentially creating a new language here, you'll want two modules: a 'lang' module that defines your language, and a 'use' module, for the program you want to write in that language. This could be done with two files, or one file using submodules.
Here, I'll show it to you using two files:
lang.rkt
#lang racket
(provide (except-out (all-from-out racket)
#%app)
(rename-out [-app #%app]))
(require syntax/parse/define)
(define-syntax-parse-rule (-app args ... proc)
(#%app proc args ...))
use.rkt
#lang s-exp "lang.rkt"
(3 2 +) ; => 5
Note though that this only changes function calls, not other forms. So:
use2.rkt
#lang s-exp "lang.rkt"
(define x 42)
(2 x *) ; => 84
Edit:
To explain what's happening in lang.rkt. It's taking the racket language, and re-exporting all of it, except the #%app macro. (For reference, all function applications in racket (f args ...) get expanded to (#%app f args ...).)
For the #%app macro, we define another macro -app, which moves the function call from the end to the start, and the uses Racket's #%app macro. We then rename -app to #%app on export.
Section 5.1 of this paper gives you an outline of the same thing, but to turn Racket into a lazy language.

How can i make the spacemacs compilation buffer split horizontally?

I am setting (setq split-width-threshold 100) in my dotspacemacs/user-config, in order to make various buffers split horizontally when the window is wide enough. This works as intended for magit status etc.
However, the compilation log buffer seems to disregard this, and always opens on the bottom.
How can i make the compilation buffer adhere to the split-width-threshold? Alternatively, how can get it to always split horizontally?
I am quite new to both emacs and spacemacs.
The reason for the compilation not to obey your settings is because spacemacs comes with purpose-mode enabled by default. If you use that, then it is a matter of modifying the purpose layouts as you wish. However if you are not using the purpose-mode, then disabling it fixes the issue for me. To just try it out you can do SPC SPC purpose-mode RET and then (with only one window opened) run the compilation.
Here's one way to do it (SPC f e d to get to your config file, then you could put this in the existing dotspacemacs-user-config function) -- here I've shown how to get both grep and compilation buffers popping up on the right:
(require 'dash)
(defun my/popwin-on-right (alist-item)
(let ((props-alist (seq-partition (cdr alist-item) 2)))
(setf (alist-get :position props-alist) '(right))
(setf (alist-get :height props-alist) '(1.0))
(setf (alist-get :width props-alist) '(0.5))
(let ((flattened (apply #'append props-alist)))
(cons (car alist-item) flattened))))
(custom-set-variables
'(popwin:special-display-config
(--map-when (-contains? '("*compilation*" "*grep*") (car it))
(my/popwin-on-right it)
popwin:special-display-config)))
or you could just set popwin:special-display-config more directly, replacing the --map-when call there with a literal list. Just view the variable's existing value e.g. using SPC SPC ielm <RET> to get nice formatting, then cut and paste it in (you'll need to quote the list using '). Or you could do what I do when I want to set a customizable variable as a literal value: use SPC SPC customize, let that update the end of your spacemacs config file with its blob of generated code, then copy out the custom-set-variables it generates into your dotspacemacs-user-config, and delete the blob of code that customize generated).
From another answer
(setq split-height-threshold nil)
(setq split-width-threshold 0)
If you want these settings to only affect compile
(defadvice compile (around split-horizontally activate)
(let ((split-width-threshold 0)
(split-height-threshold nil))
ad-do-it))

Invoke `racket` in a Racket script

General question:
Can I invoke the current racket executable from within a running Racket script?
Basically, I'd like a replacement for (system "racket ...") in the case that (find-executable-path "racket") does not return a path to the Racket executable I'm currently using.
Context:
What I really want is to try compiling a few expressions and assert that they raise compilation errors. This is for unit testing.
I don't believe you need to step outside of the executable here. Try this:
#lang racket
(require syntax/modread)
;; define a namespace anchor to attach a namespace to:
(define-namespace-anchor anchor)
;; define a namespace for expansion:
(define target-namespace (namespace-anchor->namespace anchor))
(define program-to-compile
"#lang racket
(+ 3 4)")
;; go ahead and expand
(with-module-reading-parameterization
(λ()
(parameterize ([current-namespace target-namespace])
(expand
(read-syntax
"bogus-filename"
(open-input-string program-to-compile))))))
I think I'm correct when I say that Racket is singularly clean in its ability to provide the compiler to running programs in a disciplined way.
If your goal is just to compile some racket expressions, you can do that just with either compile or compile-syntax. An example file would be:
#lang racket
(require rackunit)
(define tests
(list #'(+ 1 "3")
#'(void void)
#'(string-append 4)))
(for/list ([t (in-list test)])
(check-exn exn:fail?
(lambda () (compile t))))
Where exn:fail? is whatever exception you are looking for.
Furthermore, if you have some common syntax context you want to run your test in, you can use #` #,. So your code would end up something like this:
#lang racket
(require rackunit)
(define tests
(list #'(+ 1 "3")
#'(void void)
#'(string-append 4)))
(for/list ([t (in-list test)])
(check-exn exn:fail?
(lambda () (compile #`(module anonymous racket
#,t)))))
Finally, if your code is stored on your computer, you can use John's solution, while using file->string to convert the file into a string.
For small tests, you can also use convert-compile-time-error from the syntax/macro-testing library. It turns an expression that causes a compile-time error into an expression that raises a run-time error when evaluated. The expression uses the environment where it occurs in the module, including local bindings; you don't have to fiddle with namespaces and eval.
(check-exn #rx"bad syntax"
(lambda () (convert-compile-time-error (lambda))))
There's also convert-syntax-error (on the same page).

How to write particular function to file from SBCL interpreter?

Say I've played a bit with SBCL with no SLIME, no whatsoever, plain interpreter. Now I want to save couple of functions in a file. Not an core image, just a bits of code in a text form. How should I do that?
There are two ways to do that: use DRIBBLE and/or FUNCTION-LAMBDA-EXPRESSION
The first is to always use the Common Lisp function DRIBBLE before experimenting:
rjmba:tmp joswig$ sbcl
This is SBCL 1.1.9, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
Dribble takes a pathname for a text file. Once called, the interactive IO will be written to that file.
* (dribble "/Lisp/tmp/2013-09-06-01.text")
* (defun foo (a) (1+ a))
FOO
* (foo 10)
11
* (quit)
See the file:
rjmba:tmp joswig$ cat 2013-09-06-01.text
* (defun foo (a) (1+ a))
FOO
* (foo 10)
11
* (quit)
From above you should be able to see if you have any interesting functions entered...
You could also set your SBCL (for example using the init file) to set up dribble always at start. Calling (dribble) without arguments ends a dribble.
Next: FUNCTION-LAMBDA-EXPRESSION:
* (defun foo (b) (1- b))
FOO
Now you can call FUNCTION-LAMBDA-EXPRESSION to get the definition back. It might be slightly altered, but it should do the job to recover valuable ideas written as code:
* (function-lambda-expression #'foo)
(SB-INT:NAMED-LAMBDA FOO
(B)
(BLOCK FOO (1- B)))
NIL
FOO
If you are using sb-readline or rlwrap you press up until you hit when it got defined and copy and paste itto a file. You might have it in the termial window history too.
If none of these works only compiled definitions are available then the only way to save them is by dumping core image.
For next time, you could make a macro that stores every definition source in a special variable so that you can easily retreive them.

Racket/Scribble dynamic pdf generation

Hello all I am trying to dynamically build pdf files based on switches in a global defines file.
In file global_defines.rkt i have
#lang racket/base
(provide (all-defined-out))
(define alpha #f)
(define beta #t)
(define gamma #f)
in file foo.scrbl
#lang scribble/base
#(require "../../pdf_gen/global_defines.rkt")
#title{Getting Started}
#if[(or alpha)
#para{Test text}
""]
#if[(or beta)
(begin
#dynamic-require["bar.scrbl" 'doc]
doc)
""]
and in file bar.scrbl
#lang scribble/base
#(require "../../../pdf_gen/global_defines.rkt")
#(provide (all-defined-out))
#title{BAR}
happy marbles
so with the switches as they are currently i would expect to get something similar to the following out
Getting Started
1.BAR
happy marbles
while there are definitly other ways i can do it i would prefer to stick with scribble as it makes formatting and everything much easier than the other methods i can come up with right now. My main concerns are keeping the switches in one place and being able to pick and choose the content that is triggered by the switches being active, as there is content that will be common between several of the documents but not all of them, and quite a bit of content that only belongs in one or 2 places.
Although this answer isn't as elegant as I'd like, it works.
Basically I think you're talking about conditional compilation. In C you'd use a macro for this. In Racket let's use a macro, too (a macro which is just as brain-dead simple as a C macro).
Also we need a macro because Scribble's include-section is syntax (not a function) and must appear at the top-level. As a result, you can't use it inside of an if or when.
Given that:
define.rkt
#lang racket/base
(provide (all-defined-out))
;; Macros to conditionally include literal text.
;; Each of these should return `text`,
;; or (void) for nothing
(define-syntax-rule (when-alpha text)
text)
(define-syntax-rule (when-beta text)
(void))
;; Macros to conditionally include a .scrbl file
;; Each of these should return include-section,
;; or (void) for nothing
(require scribble/base) ;for include-section
(define-syntax-rule (when-alpha/include mod-path)
(include-section mod-path))
(define-syntax-rule (when-beta/include mod-path)
(void) #;(include-section mod-path))
Currently, this is set to show things for "alpha" but omit them for "beta". Unfortunately there's not a simple #t or #f to toggle. You need to edit the body of each one a bit more than that, as explained in the comments.
manual.scrbl example file conditionally including text and another file
#lang scribble/base
#(require "defines.rkt")
#title{Getting Started}
#when-alpha{#para{Text for alpha}}
#(when-beta/include "includee.scrbl")
includee.scrbl example file being conditionally included
#lang scribble/base
#title{BETA TEXT}
I am text for beta version.
What I don't love about this solution is that you have to create/change a pair of macros for each condition -- one for including literal text, and another for include-section-ing a .scrbl file.