I am trying to define a macro that creates commands. So far I have the following:
(defmacro create-command (command name)
`(defcommand ,name ()
(run-shell-command ,command)
))
(create-command "firefox" firefox)
Basically, I want to create a command that called "firefox", that simply launches "firefox". When I try to run the command I get the following error:
Bad Argument Type: RUN-SHELL-COMMAND.
Any idea on what is happening? Thank you!
defcommand has two argument lists, not once; the second list defines how arguents in the first list are read interactively. In your case there is no arguments, but you missed one empty list:
(defmacro create-command (command name)
`(defcommand ,name () ()
(run-shell-command ,command)))
STUMPWM-USER> (create-command "firefox" firefox)
#S(STUMPWM::COMMAND :NAME FIREFOX :CLASS T :ARGS NIL)
Related
I am trying to save data into a collection of some sort, but the program that I have is saving everything into a separate map. I want to make it one map.
(defn readFile []
(map (fn [line] (clojure.string/split line #";"))
(with-open [rdr (reader "C:/Users/Rohil/Desktop/textfile.txt")]
(doseq [[idx line] (map-indexed vector(line-seq rdr))]
(if(.contains line "201609")
(if(not(.contains line "TBA"))
(println(assoc table :code(nth(clojure.string/split line #";")3) :instructor(nth(clojure.string/split line #";")19)))
)
)
)
)
)
)
)
Any help will be appreciated.
Looks like you are adapting to clojure :-) I went to the same process. Hang on, it will be worth it!
First: it is important to realize that map will save the result of the function into a new collection. Like cfrick mentions, println returns nil and assoc does not change a map.
I'm guessing a bit here what you are trying to do: You want to have a collection of dicts, where every dict has two keys, like so:
[
{ :code 1 :instructor "blah"}
{ :code 2 :instructor "boo" }
]
You need these values to come from a file, but you only want to save the lines where the line contains "201609" but not "TBA"
First some general remarks:
You probably want to split this function into smaller parts. One could be the check for lines (contains 201609 but not tba ), another could read the file...
I know it is the title of your question, but most likely there is a better way than to change a global variable. Maybe you could make the function readFile return the table?
try if you can pass in arguments to your function.
I'm not sure what you are trying to do with the line (doseq [[... Please give us more context there. I will ignore it
Here is a possible solution:
(ns test
(:require [clojure.string :as s]
[clojure.java.io :as io]))
(defn line-filter [include exclude line]
(and (not (s/includes? line exclude))
(s/includes? line include)))
(defn process-line [line]
(let [line-parts (s/split line #";")
code (nth line-parts 3)
instructor (nth line-parts 19)]
{:code code :instructor instructor}))
(defn read-file [file-name]
(s/split (slurp (io/resource file-name)) #"\n"))
(defn parse-lines [lines]
(map process-line lines))
(defn read-file-and-parse
"This function will read a file, process the lines, and output a collection of maps"
[filename search-for exclude]
(parse-lines
(filter #(line-filter search-for exclude %)
(read-file filename))))
you could now call this function like this: (read-file-and-parse "test.txt" "201609" "TBA")
If you want to add the result of this function into your table, you can use concat. But again, this will return a new version of your list (with new entries added) and not change the one you defined earlier.
Welcome to functional programming :-)))
I'm using the sketch library on this function:
(defun init-plot (&optional (title "Plot Window")
(x-size 250) (y-size 250))
(defsketch window ((width x-size)(height y-size)(title title)))
(make-instance 'window ))
Basically is a three optional arguments function, that make a class sketch a create a instance. the function works but it has this warning:
; In INIT-PLOT: Unused lexical variable TITLE
with this, the title option doesn't work, but this variables are on different scopes, so I do not get why I have to change the name of the first variable. because whithout changing it does not work
defscket is a macro that wraps defclass
(defmacro defsketch (sketch-name bindings &body body)
...
So I don't get the point what is happening here
Starting REPL clisp-2.49-r8:
clisp -K full
Trying to execute something from DBUS module test
http://clisp.cvs.sourceforge.net/viewvc/clisp/clisp/modules/dbus/test.tst
(listp (show (multiple-value-list (ext:module-info "dbus" t)) :pretty t))
Getting:
*** - EVAL: undefined function SHOW
Where I can find this SHOW function?
Sorry...
It was defined in tests/tests.lisp
(defun show (object &key ((:pretty *print-pretty*) *print-pretty*))
"Print the object on its own line and return it. Used in many tests!"
(fresh-line) (prin1 object) (terpri) object)
Question: How to force a s-exp to be evaluated before passing to a function expecting parameter of string type or else.?
This code is fine (no error):
(setf (slot-value (ole sheet :range "A1:B1") 'value)
`(("123" "456"))))
However, when passing a s-exp such as (first line) instead of "123":
(setf line '("123" "456"))
(setf (slot-value (ole sheet :range "A1:B1") 'value)
`(((first line) (second line)))))
There is error message:
The value FIRST is not of the expected type (OR
STRING
FIXNUM
SINGLE-FLOAT
DOUBLE-FLOAT).
[Condition of type TYPE-ERROR]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT-BREAK] Reset this thread
3: [ABORT] Kill this thread
I know what the problem is. But is there way get rid of this restriction? Because we would need to put the line of code inside a loop, so can't fix the parameter value to such as "123"...
I try using macro:
(defmacro set-line (par1 par2)
`(setf (slot-value (ole sheet :range "A1:B1") 'value)
`((,par1 ,par2))))
However, it doesn't work. Still the same error message saying the wrong type (first line)...
(set-line (first line) (second line))
Also I don't know how to escape the backquote ` if it appears inside macro body. I have tried put a \ in front of backquote inside the macro body, but then the \ would also appear upon macro expand.
`(setf xxx ` <--- another backquote
`(setf xxx \` <--- this can't escape backquote inside macro body
Thanks.
Background: when playing with Win32 OLE Excel example in:
https://github.com/quek/cl-win32ole/blob/master/example/excel.lisp
You are missing the basics of quotation. Your expression
? `(("123" "456")) ; quasiquote
(("123" "456"))
is a list containing a list and can also be created using the function LIST as
? (list (list "123" "456")) ; list
(("123" "456"))
To use expressions, you can either use unquote (note the preceding comma)
? `((,(first line) ,(second line))) ; quasiquote with unquote
(("123" "456"))
or, better
? `(,line)
(("123" "456"))
or use list :
? (list line)
(("123" "456"))
I use the async to call async function in elisp.
First of all I test the readme code in github and it works well.
Then I write a test code :
(defun async-function ()
(async-start
;; What to do in the child process
(lambda ()
(shell-command-to-string "~/test.sh"))
;; What to do when it finishes
(lambda (result)
(message "Async process done, result is: %s" result)))
And the test.sh code is very simple:
#! /usr/bin/env sh
sleep 2
echo "shell finish"
It works , But it failed when I change the lisp code like that :
;;;###autoload
(defun test ()
(shell-command-to-string "~/test.sh"))
(defun async-function ()
(async-start
;; What to do in the child process
(lambda ()
(test))
;; What to do when it finishes
(lambda (result)
(message "Async process done, result is: %s" result)))
The result is:
error in process sentinel: Symbol's function definition is void: test
I use the autoload function to load the function file but the result tell me that the file can not found.
I have no idea what happen about that and how to fix.
async.el works by spawning another Emacs process in which to evaluate the expressions. In this case you define the test function in your main Emacs process but the async Emacs process has no access to the functions and variables from your main process. If you want to specify functions for your async calls to use, put them in a file and load that file in your async function. But remember that variables and the like will not transfer over.
Here is a an example, this is in one file:
;; ~/.emacs.d/my-functions.el
(defun test ()
(sit-for 2)
"Hello, World!.")
And this is somewhere else:
;; somewhere else
(async-start
(lambda ()
(load-file "~/.emacs.d/my-functions.el")
(test))
(lambda (result)
(message "result: %s" result))) ;; will message hello world
Regarding sharing variables, this is not supported by async. What you CANNOT do is start up an async function that continually modifies a variable and expect to have access to it on the main emacs process, or even just pass the variable into the async lambda, because the symbol won't be evaluated until it's on the new process where it won't exist.
We can make use of Lisp's backquote syntax to pass our variables into our async function by value. Below is a very hacky way of using a local variable and function in an async function.
;; We will declare a local variable `myvar'
(setq myvar "Bob")
;; Here is a simple function, notice that it does not
;; refer to other non standard functions or other local variables
(defun hello (name)
(format "Hello, %s!" name))
(defun my-async-function ()
(async-start
;; notice the backquote!
`(lambda ()
;; in our async lambda we dont use the local `myvar' variable,
;; instead we are replacing it with the current local value of `myvar'
(set 'myvar ,myvar)
;; we can also do this by actually obtaining the lambda expression
;; behind `hello' and putting that inside our lambda
(fset 'hello ,(symbol-function 'hello))
;; then we wait!
(sit-for 1)
;; now we are modifiying the async copy of `myvar'
(setq myvar (concat myvar " Johnson"))
;; here we want the result of the async lambda to be a call to our
;; `hello' function, but we also want to update our local version
;; of myvar with its value in th async process, so we will return
;; a list of both values which we can handle in our callback
(list myvar (hello myvar)))
(lambda (result)
;; once we get the results we'll update our local version of `myvar'
;; with the value returned by the async function
(setq myvar (first result))
;; then we can print out the message we recieved from the output
;; of our async `hello' call.
(message "The new value myvar is: %s\nThe result of the function was: %s"
myvar
(second result)))))
;; executed top down, the async callback will message:
;;The new value myvar is: Bob Johnson
;;The result of the function was: Hello, Bob Johnson!
I have abstracted out the concept of replacing variables and functions with their immediate value with a macro: value-bound-lambda, you can get the macro and see an example here:
value-bound-lambda example
Just want to share a technique I use to run a custom function using async and not wanting to hard-code the file path. Assume I want to run the function my-custom-function that is in the file my-custom.el (i.e. "~/emacs.d/my-custom/my-custom.el"). So the symbol-file will return the filename where the function is defined and file-name-directory returns it's parent directory.
(let ((script-filename (file-name-directory (symbol-file 'my-custom-function))))
(async-start
`(lambda()
(add-to-list 'load-path ,script-filename)
(require 'my-custom)
(my-custom-function)
....