I'm a newbie in common lisp, i want to do some (maybe advanced file reading)
so lets say i have example1.txt, example2.txt and example3.txt.
example1.txt has the following:
Born 9 October 1940
Died 8 December 1980 (aged 40)
John Winston Ono Lennon, MBE (born John Winston Lennon; 9 October 1940
– 8 December 1980) was an English musician, singer and songwriter who
rose to worldwide fame as a founder member of the Beatles
so what i want to do is:
i get prompted to enter a name, I enter Lennon.
if the file contains the word lennon, keep reading, else read example2, I don't know how to use the buffer in LISP, in C++ or perl, that'd be so easy for me and wouldn't had asked this question, but i have to do it in lisp. I want to return the index of the element as well so for example, if i typed "musician" i want it to continue reading, and not to start from 0.
according to this book i may need a function called READ-SEQUENCE is that true? and how to use it? by the way, I'm on windows and using LispWorks.
(defun find-word-in-file (word file)
(with-open-file (stream file)
(loop
:for line := (read-line stream nil nil)
:for found := (and line (search word line))
:until (or (not line) found)
:summing (length line) :into position
:finally (return (when found (+ position found))))))
(find-word-in-file "Lennon" "./example.txt")
;; 79
Something like this would do, I guess.
Related
I am trying to learn Common Lisp with the book Common Lisp: A gentle introduction to Symbolic Computation. In addition, I am using SBCL, Emacs, and Slime.
By the end of chapter 9, the author shows the dribble tool.
He shows the following:
I tried to reproduce the commands presented by the author. Considering the inputs, the only difference was the fact that I put a different location to save the file. In my environment, I did:
CL-USER> (dribble "/home/pedro/miscellaneous/misc/symbolic-computation/teste-tool.log")
; No value
CL-USER> (cons 2 nil)
(2)
CL-USER> '(is driblle really working?)
(IS DRIBLLE REALLY WORKING?)
CL-USER> "is dribble useful at all?"
"is dribble useful at all?"
CL-USER> (dribble)
; No value
The file was indeed created:
$ readlink -f teste-tool.log
/home/pedro/miscellaneous/misc/symbolic-computation/teste-tool.log
Note that I did not get messages such as "Now recording in file --location---" in the REPL while I was typing. But this may vary according to the Lisp implementation.
The big surprise was that, unfortunately, the file was empty. Thus, dribble did not work as expected.
Did I do something wrong?
Yes, by default, within Slime I don't think this works.
It will work within the SBCL Repl:
➜ sbcl
This is SBCL 2.0.1.debian, 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 "dribble-test.lisp")
* (* 8 5)
40
* "Will this work?"
"Will this work?"
* (dribble)
* %
Which can be confirmed:
➜ cat dribble-test.lisp
* (* 8 5)
40
* "Will this work?"
"Will this work?"
* (dribble)
Saving "REPL history" seems less useful with Slime IMO because of all the "non-REPL evaluation" that you do by e.g. selecting a function or an expression or region and evaluating that in the REPL.
To actually save and view history within Slime, see slime-repl-save-history and associated functions; you can even merge histories from independent Repls if you so choose :-)
This question already has answers here:
Common Lisp: Why is cl lnterning symbols to the wrong package when reading from file?
(2 answers)
Closed 2 years ago.
This seems to be a very simple question, but I am still a beginner in common lisp.
I tried to load files like the following. Without packages the symbols 'year
'month etc. can be compared to in every file.
;;; file db.lisp
((year 2010
(month 5
(1 100 "A")
(2 -5 "B"))
(balance 10)
(month 6
(1 -7 "C")
(2 -8 "D")))
(load-from-csv-format-1 "db2011.csv")
(load-from-csv-format-2 "db2012.csv"))
I managed to convert the existing lisp code the following
(defpackage :db
(:use :common-lisp :db.csv-format-1))
(in-package :db)
(defun read-db ()
(let ((db (with-open-file (stream "db.lisp")
(read stream))))
...
(case (car x)
(year (expand-year x))
(load-from-csv-format-1 (load-format-csv-format-1-impl (second x)))
(load-from-csv-format-2 (load-format-csv-format-1-impl (second x)))
...
Now all symbols belong to the package :db. This has one disadvantage for me, as
all calls to read-db have to be done from within :db. If I now want to separate
all the different csv-formats in different packages, it doesn't work anymore, since
e.g. 'balance below belongs to the db.csv-format-1 package which cannot be compared
against the db::balance symbol.
(defpackage :db.csv-format-1
(:use :common-lisp)
(:export :load-from-csv-format-1-impl))
(in-package :db.csv.format-1)
(defun load-format-csv-format-1-impl (path)
(list 'balance 20))
So my question is, how is this done properly in lisp? Can one specify to read somehow,
in which package to create symbols and then access these symbols somehow outside this
package?
read
interns whatever it reads in
the package *package* so you can
do this:
(defun read-db ()
(let* ((*package* (find-package #:db))
((db (with-open-file (stream "db.lisp")
(read stream)))))
...))
PS. As a beginner, you might enjoy reading some of the books recommended in Resources for learning Lisp.
in Paul Graham's Bel specification (bel reference)
he defines the 'mac' macro this way:
(mac mac (n . rest)
`(set ,n (macro ,#rest)))
Isn't this circular? how does the interpreter know what the value of mac is if you are using 'mac' to define mac?
This isn't being used to define the mac operator. The compiler already has built-in knowledge of how to compile macros.
This is used to make the definition visible to application code.
This kind of apparent circularity can be found in most Lisp implementations. Many years ago I was confused when I saw this in the Symbolics source code:
(defun car (cons)
(car cons))
(defun cdr (cons)
(cdr cons))
(defun cons (car cdr)
(cons car cdr))
There's similar code in SBCL.
It works because the compiler has built-in code generators for these functions. This code is there to create runtime function objects for them, so you can use things like
(symbol-function 'car)
Bel isn't implemented, so there is no such problem. The human intellect reading the specification isn't fazed by the circularity. We read it as "given that we already have a working macro mac, here is how it can be defined using itself, and this definition is to be understood as specifying what mac does."
Someone implementing Bel would just use that definition as a guide to create a hand-expanded version of mac that doesn't rely on the mac syntactic sugar.
The hand-expanded version might look like this:
(set mac (macro (n . rest) `(set ,n (macro ,#rest))))
So that is to say, we use set to associate a macro definition with the mac symbol like the mac macro would if we already had it. Once we do this, we then have mac; we can process the original definition from the spec, if we wish.
How do you embed control characters (ie " or ' or :) in cl-dbi queries for sqlite3?
currently using a make-string-output/get-output-stream-string to build a variable that contains quoted data (json). Now, I want to be able to store the data in a sqlite3 db, but I'm obviously building the string wrong, because I get an error
DB Error: unrecognized token: ":" (Code: ERROR)
how do I escape characters in cl-dbi to pass them through to sqlite3?
EDIT - here's a brief passage of the JSON data that I'm trying to store (as text) in the sqlite3 db:
{
"type": "artificial",
Update: GAH! Took me a day to find an errant : in the prepared query string. :/
As far as I can make out, what you are trying to do is generate, in Lisp, some string which contains valid SQL, which itself contains an SQL literal string.
First of all this is an instance of an antipattern I call 'language in a string'. I keep thinking I have a big diatribe about this to point people at but it seems I haven't. Suffice it to say it's kind of the antithesis of what Lisp people have tried to achieve for more than 60 years and it's why we have SQL injection attacks and a lot of the other crap that afflicts us. But that battle is long lost and all we can do is try to avoid actually drowning in the sea of mud and rotting bits of people that now litters the battlefield.
So, to do this you need to be able to do two things.
You need to be able to generate an SQL literal string from a sequence of characters (or from a string). This means you need to know the syntax of literal SQL strings and in particular what characters are legal in them and how you express characters which are not.
You need to be able to interpolate this string into a CL string.
The second of these is trivial: this is what format's ~A directive does. Or if you want to get fancy you could use cl-interpol.
For the first, I don't know the syntax of SQL literal strings, but I will give an example which assumes the following simple rules:
literal strings are delimited by " characters;
the character \ escapes the following character to remove it of any special significance;
all other characters are allowed (this is almost certainly wrong).
Well, there are lots of ways of doing this, all of which involve walking along the sequence of characters looking for the ones that need to be escaped. Here is something reasonably horrible and quick which I wrote. It needs a macro called nlet which is Scheme's 'named let' construct, and it assumes TRO in the implementation (if your implementation does not do this, get one that does).
(defmacro nlet (name bindings &body forms)
"named let"
(multiple-value-bind (vars vals) (values (mapcar (lambda (b)
(etypecase b
(symbol b)
(cons (first b))))
bindings)
(mapcar (lambda (b)
(etypecase b
(symbol 'nil)
(cons
(unless (null (cddr b))
(error "bad binding ~A" b))
(second b))))
bindings))
`(labels ((,name ,vars ,#forms))
(,name ,#vals))))
(defun ->sql-string (seq)
;; turn SEQ (a sequence of characters) into a string representing an
;; SQL literal string (perhaps)
(nlet loupe ((tail (coerce seq 'list))
(accum '()))
(if (null tail)
(coerce (cons #\" (nreverse (cons #\" accum))) 'string)
(destructuring-bind (first . rest) tail
(loupe rest
(case first
((#\\ #\")
(append (list first #\\) accum))
(otherwise
(cons first accum))))))))
So now:
> (->sql-string "foo")
"\"foo\""
> (->sql-string '(#\f #\\ #\o #\" #\o))
"\"f\\\\o\\\"o\""
This is made ugly by the Lisp printer, but (see above) we can see what the strings actually are:
> (format t "~&select x from y where x.y = ~A;~%"
(->sql-string '(#\f #\\ #\o #\" #\o)))
select x from y where x.y = "f\\o\"o";
nil
And you can see that the SQL literal string obeys the rules I set out above.
Before using anything like this check what the rules are, because if you get them wrong you are possibly open to SQL injection attacks.
This program was taken from Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp by Peter Norvig, 1992, Morgan Kaufmann Publishers, Inc. If I compile and load it into a debug window, how would I use it?
; This function returns a random element of the list choices
(defun random-elt (choices)
"Choose an element from a list at random."
;; elt returns the (n + 1)th element of the list choices
;; random returns a random integer no large than the number of
;; elements in the list choices
(elt choices (random (length choices))))
; This function returns a random element of the given set and returns
; it in a list
(defun one-of (set)
"Pick one element of set, and make a list of it."
(list (random-elt set)))
; Define a sentence as a noun-phrase + verb phrase
(defun sentence () (append (noun-phrase) (verb-phrase)))
; Define a noun phrase as an article + noun
(defun noun-phrase () (append (Article) (Noun)))
; Define a verb phrase as a verb + a noun phrase
(defun verb-phrase () (append (Verb) (noun-phrase)))
; This function returns a randomly selected article
(defun Article () (one-of '(the a)))
; This function returns a randomly selected noun
(defun Noun () (one-of '(man ball woman table)))
; This function returns a randomly selected verb
(defun Verb () (one-of '(hit took saw liked)))
Looking at that code I see the only function not used in another is sentence. If you enter (sentence) you'll get a random sentence like:
(sentence) ;==> (THE WOMAN TOOK A TABLE)
Typically I would edit the file using something like SLIME/Emacs, Clozure CL, LispWorks, Allegro CL ... or anything other which has an editor which can talk to Common Lisp.
If you put the code in a buffer, then compile the buffer. In SLIME/Emacs use control-c control-k or meta-x slime-compile-and-load-file. This compiles the whole file and loads the compiled code into the running inferior Common Lisp.
In the LispWorks IDE I would just go into the buffer menu and execute compile.
Then go to the listener (aka REPL) and execute (sentence). Page 34 to 38 in Norvig's excellent book explain the code and how to use it in detail.