I am reading Ocaml Style guide on nested let-in of Ocaml.
http://www.seas.upenn.edu/~cis341/programming_style.html#16
It is suggested that
Indenting nested let expressions: Blocks of code that have nested let expressions should not be indented.
Bad:
let x = exp1 in
let y = exp2 in
x + y
Good:
let x = exp1 in
let y = exp2 in
x + y
However, what do you think about how to indent my following program.
let f =
let g = 3 in
g + 2
The above is indented by emacs. But apparently, this indenting of emacs violates the style guide I cited earlier. To follow the style, shouldn' t it be more like this one?
let f =
let g = 3 in
g + 2
Thank you for your ideas.
#Gilles: In my current default Tuareg mode, I get such indenting, which is diffrent from yours
let f =
let g = 3 in
let h = 4 in
g + 2
could you explain which configuration should I do to make my Tuareg mode indent as yours?
The official caml-mode (part of the standard Ocaml distribution) defaults to not intenting the body of a let expression:
let f =
let g = 3 in
let h = 4 in
g + 2
This is the style used by the authors of Ocaml (hence the Right style). In my experience the official mode matches the official style very well (unsurprising since it's from the same people). If you're getting something different, you (or the person or distribution who installed the mode on your machine) must have configured it.
Tuareg mode puts the same indentation on the snippet above on my machine (Debian squeeze). Different versions have different indentation defaults; in particular, this is the docstring for tuareg-in-indent on 2.0.1:
How many spaces to indent from a in keyword.
Upstream recommends 0, and this is what we default to since 2.0.1 instead of the historical tuareg-default-indent.
I think Tuareg does have some strange behavior indenting nested let-in. add these lines to come back to "default" ocaml indenting style, suggested by
C. TROESTLER
(add-hook 'tuareg-mode-hook
(function (lambda ()
(setq tuareg-in-indent 0)
(setq tuareg-let-always-indent t)
(setq tuareg-let-indent tuareg-default-indent)
(setq tuareg-with-indent 0)
(setq tuareg-function-indent 0)
(setq tuareg-fun-indent 0)
(setq tuareg-parser-indent 0)
(setq tuareg-match-indent 0)
(setq tuareg-begin-indent tuareg-default-indent)
(setq tuareg-parse-indent tuareg-default-indent); .mll
(setq tuareg-rule-indent tuareg-default-indent)
(setq tuareg-font-lock-symbols nil)
)))
Related
Emacs version: 26.3
Slime version: 2.26.1
I start up Emacs.
I open up a simple .lisp file.
(defun testfn (x y)
(+ x y))
(defmacro testmc (form)
form
`(list 1 2 3))
I place my cursor over the symbol defun and issue the keyboard-command M-. (slime-edit-definition).
This should bring me to the definition of defun.
But it doesn't.
It brings me here:
I place my cursor over the symbol defmacro and issue the keyboard-command M-. (slime-edit-definition).
This should bring me to the definition of defmacro.
But it doesn't.
It brings me here:
Why does it do this & how do I fix this
Notice there is a warning in the REPL when trying to find the source of DEFUN:
WARNING: inconsistent 2 form-number-translations
You can replicate it yourself in the REPL:
CL-USER> (let ((slynk::*buffer-package* (find-package :cl))
(slynk::*buffer-readtable* *readtable*))
(slynk:find-definitions-for-emacs "DEFUN"))
WARNING: inconsistent 2 form-number-translations
(("(DEFMACRO DEFUN)"
(:LOCATION (:FILE "/home/chris/data/src/sbcl/src/code/macros.lisp")
(:POSITION 4140)
(:SNIPPET "(setq doc nil)
(let* (;; stuff shared between LAMBDA and INLINE-LAMBDA and NAMED-LAMBDA
(lambda-guts `(,#decls (block ,(fun-name-block-name name) ,#forms)))
(lambda `(lambda ,lambda-list ,#lambda-guts))
(named-lambda `("))))
To find where the warning comes from, you could do as I did first and do a textual search on the repository, or you could use the following alternate method that works better, namely invoke the debugger on warnings:
(handler-bind ((warning (lambda (c) (invoke-debugger c))))
(let ((slynk::*buffer-package* (find-package :cl))
(slynk::*buffer-readtable* *readtable*))
(slynk:find-definitions-for-emacs "DEFUN")))
This comes from SLYNK-SBCL::FORM-NUMBER-POSITION, and the interesting value in the debugger is the source location obtained from SBCL:
#<SB-INTROSPECT:DEFINITION-SOURCE {10369C50F3}>
--------------------
The object is a STRUCTURE-OBJECT of type SB-INTROSPECT:DEFINITION-SOURCE.
PATHNAME: #P"SYS:SRC;CODE;MACROS.LISP"
FORM-PATH: (5)
FORM-NUMBER: 89
CHARACTER-OFFSET: 3917
FILE-WRITE-DATE: 3825178034
PLIST: NIL
DESCRIPTION: NIL
It says the source is the fifth toplevel form in the file (which corresponds to the character offset), and from here, the FORM-NUMBER is the 89th form in a depth-first search walk of the form (this comes from the structure's docstring).
But, if I recompile the function FORM-NUMBER-POSITION with DEBUG set to 3, the toplevel form read at this position, TLF is NIL:
1: (SLYNK-SBCL::FORM-NUMBER-POSITION #S(SB-INTROSPECT:DEFINITION-SOURCE :PATHNAME #P"SYS:SRC;CODE;MACROS.LISP" :FORM-PATH (5) :FORM-NUMBER 89 :CHARACTER-OFFSET 3917 :FILE-WRITE-DATE 3825178034 :PLIST NIL..
Locals:
DEFINITION-SOURCE = #S(SB-INTROSPECT:DEFINITION-SOURCE :PATHNAME #P"SYS:SRC;CODE;MACROS.LISP" :FORM-PATH (5) :FORM-NUMBER 89 :CHARACTER-OFFSET 3917 :FILE-WRITE-DATE 3825178034 :PLIST NIL :DESCRIPTION NIL)
FORM-NUMBER = 89
PATH-TABLE = #((0 0))
POS-MAP = #<HASH-TABLE :TEST EQ :COUNT 126 {103B227EA3}>
POS-MAP#1 = #<HASH-TABLE :TEST EQ :COUNT 126 {103B227EA3}>
STREAM = #<SB-IMPL::STRING-INPUT-STREAM {7F3E0350D953}>
TLF = NIL
TLF#1 = NIL
TLF-NUMBER = 5
In read-source-form, you can see that the form is being read inside a (ignore-errors (read ...)) form, which returns NIL in case of error. I tried calling (read ...) only but this somehow did not invoke the debugger, so I did the same thing as above and explicitly invoked it on any condition.
There is an error, namely that the package "SB-XC" does not exist, which is expected since, if I am not mistaken, this is a package that only exists during the compilation of SBCL itself.
I think you should contact the SBCL SLY developers and file a bug for this directly, they would certainly have a better idea of how to fix the behaviour (feel free to link to your question in addition to giving the usual details of the bug report).
I'm seeing pretty much what you're seeing.
Defun (line 280 of defboot.lisp) is a macro, which is defined in terms of defun-expander (line 230 of defboot.lisp) which is what you're seeing.
Whereas, defmacro takes you directly to its definition (line 15 of defmacro.lisp) which is what you're seeing.
It seems to be doing useful things.
I defined a new function 'addmore'
(defun addmore (x y z)
(testfn x (testfn y z)))
I compiled it all, and M-. on 'addmore' takes me to the definition of testfn.
So I think it's all working.
I'd like to write a simple macro that shows the names & values of variables. In Common Lisp it would be
(defmacro dprint (&rest vars)
`(progn
,#(loop for v in vars
collect `(format t "~a: ~a~%" ',v ,v))))
In Julia I had two problems writing this:
How can I collect the generated Expr objects into a block? (In Lisp, this is done by splicing the list with ,# into progn.) The best I could come up with is to create an Expr(:block), and set its args to the list, but this is far from elegant.
I need to use both the name and the value of the variable. Interpolation inside strings and quoted expressions both use $, which complicates the issue, but even if I use string for concatenation, I can 't print the variable's name - at least :($v) does not do the same as ',v in CL...
My current macro looks like this:
macro dprint(vars...)
ex = Expr(:block)
ex.args = [:(println(string(:($v), " = ", $v))) for v in vars]
ex
end
Looking at a macroexpansion shows the problem:
julia> macroexpand(:(#dprint x y))
quote
println(string(v," = ",x))
println(string(v," = ",y))
end
I would like to get
quote
println(string(:x," = ",x))
println(string(:y," = ",y))
end
Any hints?
EDIT: Combining the answers, the solution seems to be the following:
macro dprint(vars...)
quote
$([:(println(string($(Meta.quot(v)), " = ", $v))) for v in vars]...)
end
end
... i.e., using $(Meta.quot(v)) to the effect of ',v, and $(expr...) for ,#expr. Thank you again!
the #show macro already exists for this. It is helpful to be able to implement it yourself, so later you can do other likes like make one that will show the size of an Array..
For your particular variant:
Answer is Meta.quot,
macro dprint(vars...)
ex = Expr(:block)
ex.args = [:(println($(Meta.quot(v)), " = ", $v)) for v in vars]
ex
end
See with:
julia> a=2; b=3;
julia> #dprint a
a = 2
julia> #dprint a b
a = 2
b = 3
oxinabox's answer is good, but I should mention the equivalent to ,#x is $(x...) (this is the other part of your question).
For instance, consider the macro
macro _begin(); esc(:begin); end
macro #_begin()(args...)
quote
$(args...)
end |> esc
end
and invocation
#begin x=1 y=2 x*y
which (though dubiously readable) produces the expected result 2. (The #_begin macro is not part of the example; it is required however because begin is a reserved word, so one needs a macro to access the symbol directly.)
Note
julia> macroexpand(:(#begin 1 2 3))
quote # REPL[1], line 5:
1
2
3
end
I consider this more readable, personally, than pushing to the .args array.
Let's say I have a special var:
(defvar x 20)
then I do the following:
(let ((x 1)) (eval '(+ x 1))
which evaluates to 2.
According to CLHS, eval "Evaluates form in the current dynamic environment and the null lexical environment". So, I would expect to get 21 instead of 2.
Am I missing something?
Now if I have no dynamic binding for symbol y, evaluating
(let ((y 1)) (eval '(+ y 1))
I get condition: "The variable Y is unbound", which makes sense, since there is no dynamic binding for y.
Note: I'm using SBCL 1.0.57
Appreciate your help in advance!
in your example x is special which means it is bound in the dynamic environment
y is not special, so it is bound in the lexical environment
so at the time of the first eval the environments could be represented like this:
dynamic environment: { x : 1 } -> { x : 20, ...other global variables... } -> nil
lexical environment: nil
the symbol x is special so eval looks up x in the current dynamic
environment and finds x = 1
assuming it was run in same lisp as the last example, the environment of your second eval looks like this:
dynamic environment: { x : 20, ...other global variables... } -> nil
lexical environment: { y : 1 } -> nil
the symbol y is not special so eval looks up y in the null
lexical environment -- not the current lexical environment -- and finds nothing.
this makes sense when you realize that lisp is usually compiled, and the lexical
environment can be optimized down to simple mov instructions in some cases.
DEFVAR declares its variables special. Globally, everywhere. You can also not remove this easily.
That's also the reason you should never use common names like x, i, list as variable names for DEFVAR. Make sure that you use *x*, *i* and *list* instead. Otherwise all variables, even local ones, with these common names are declared special.
I'm a ClojureScript newbie using emacs, cider, cljsbuild, and austin with slimerjs on a Windows machine. I've noted that sometimes when I type into the clojurescript repl, an extra ^M character and nil are appended to the output (but the return value is not nil, as indicated by the output of the repl enclosed below). The output before the ^M is colored red, while the nil output is black. What could be causing this, and how can I fix this? (Should I be reporting this as an issue to one of the project's trackers?)
cljs.user> 1
1
cljs.user> true
true
cljs.user> (reduce + [1 2 3])
6
cljs.user> (list [1 2 3])
([1 2 3])
cljs.user> reduce
#<function (a,e,f){switch(arguments.length){case 2:return b.call(this,
a,e);case 3:return c.call(this,a,e,f)}throw Error("Invalid arity: "+arguments.length);}>^M
nil
cljs.user> js/document
#<[object HTMLDocument]>^M
nil
cljs.user> (def d js/document)
#<[object HTMLDocument]>^M
nil
cljs.user> (nil? d)
false
^M is windows line ending. Answer how ho hide it in Emacs can be found here.
Printing of nil in general is normal behaviour and it's not specific to Clojurescript or Emacs. All forms return a value (which may be nil) and also may produce side-effects:
cljs.user> (println 1)
1 ; Side effect - printed value
nil ; Result of evaluation
However returning nil for js/document, (def d js/document) and similar "not-nil" forms is Austin specific behaviour and probably can be treated as minor bug.
I can't think of any possible use case for this, but as an exercise to try to wrap my mind further around Clojure's macros, I'm trying to write a macro that will swap the values assigned to two symbols.
Here are two things that I tried:
Method 1:
(defmacro swap [x y]
`(let [tmp# ~x]
(def x ~y)
(def y ~tmp#)))
Method 2:
(defmacro swap [x y]
`(let [tmp# ~x]
(alter-var-root #'x (fn [] ~y))
(alter-var-root #'y (fn [] ~tmp#))))
Here is the code I use to test it:
(def four 4)
(def five 5)
(swap four five)
(printf "four: %d\nfive: %d" four five)
Expected output:
four: 5
five: 4
However, using either version of the macro, I get a java.lang.RuntimeException: Unable to resolve symbol: tmp# in this context. Am I using auto gensym incorrectly?
Using method 1, I was able to get it to run by changing the last line to (def y tmp#))) (taking out the ~ before tmp#), however I get the output four: 4\nfive: 5 which is not swapped.
Ignoring the fact that mutating vars like this is a bad idea, let's assume you really want to do it anyway. Your problem is two-fold:
You have an unquote on ~tmp#, where you just want tmp#
You're missing an unquote on x and y: you want to (def ~x ~y) and (def ~y tmp#)
The version you wrote always assigns to the vars named x and y, instead of modifying the vars provided by the user.