I'm trying to learn Common Lisp (sbcl) and getting practice with basic defuns. I'm trying to write one now that adds the lengths of all the strings in a list.
An early step is testing whether the first element is a string. I assumed you could call this with
(stringp (car '(s1 s2)))
where s1 and s2 are strings. Testing s1 with stringp, and asking for the car of the list seem to work ok, but combining them together doesn't give me what I expect:
CL-USER> (car '(s1 s2))
S1
CL-USER> (stringp s1)
T
CL-USER> (stringp (car '(s1 s2)))
NIL
Am I misunderstanding the stringp function, or the way lists work?
Thank you
'(s1 s2) is a list containing the symbols s1 and s2. So (car '(s1 s2)) returns the symbol s1 (as you can see by the fact that the REPL prints S1 and not whatever string is stored in the variable s1. Since a symbol is not a string, stringp returns false.
If you actually use a list of strings, it will work as you expect:
* (car (list s1 s2))
"contents of s1"
* (stringp (car (list s1 s2)))
T
The QUOTE prevents the evaluation of its enclosed form. The enclosed form is returned as is.
(car '(s1 s2)) returns S1. Which is a symbol and not a string.
If you evaluate s1, then Lisp returns its value. But that uses another evaluation step.
If you look at s1 as a symbol, then it stays a symbol if you tell Lisp:
CL-USER > 's1
S1
CL-USER > (stringp 's1)
NIL
Related
I need return True or False
True if at least one lowercase character
False no lowercase characters
I tried do it with loop and lambda function
Something like this
(defun check-lower-word (word)
(loop
for ch across word
((lambda (c) (if (lower-case-p c) return T) ch)
)
)
I need False if never worked "if"
With a predefined function, you could use some (manual):
CL-USER> (some #'lower-case-p "AbC")
T
CL-USER> (some #'lower-case-p "ABC")
NIL
There is a similar operation for the loop syntax (manual):
CL-USER> (loop for x across "AbC" thereis (lower-case-p x))
T
CL-USER> (loop for x across "ABC" thereis (lower-case-p x))
NIL
Finally, note that loop always returns nil when the iteration terminates without producing a result, so a less concise use of loop could be:
CL-USER> (loop for x across "AbC" if (lower-case-p x) do (return t))
T
CL-USER> (loop for x across "ABC" if (lower-case-p x) do (return t))
NIL
Code errors
You code is not balanced with respect to parentheses, there is a missing closing parenthesis at the end:
(defun check-lower-word (word)
(loop
for ch across word
((lambda (c) (if (lower-case-p c) return T) ch)
)
) ; <-- closes "(loop"
The syntax error in your loop should have raised an error, it does not make sense to write an expression EXPR directly in (loop for c across w EXPR), there should be a preceding do.
The literal ((lambda (c) E) ch) can be directly written as E where every occurence of the variable c is substituted by ch, namely:
(if (lower-case-p ch) return T)
The use of an intermediate literal lambda brings nothing here.
Also, the above reads as: if ch is lowercase, the value of the if is the value bound to the return variable, otherwise it is T. You are indeed missing parens around (return T). A "one-armed" (if T X) is best written as (when T X).
Another approach
You already have an example with some and loop, you can also use a short-circuiting map:
(defun check-lower-word (word)
(block nil
(map ()
(lambda (c)
(when (lower-case-p c)
(return t)))
word)))
A call to MAP with nil as a first argument means the sequence is iterated for effects and returns nil. For each character in the sequence (list or vector), when the character is lower-case, return T. The return exits the iteration early up to the NIL block.
I did it as
(defun check-lower-word (word)
(block outer
(loop
for ch across word do
(if (lower-case-p ch) (return-from outer T))
)
)
)
I am currently working on a homework assignment with MIT scheme, and have come across a few problems that are supposedly very short, though I'm a bit confused as to how to implement some of them.
One problem asks me to write a function that returns a list with all the integers removed. I did manage to solve that,
(define (f2a lst) (map (lambda(x) (remove number? x)) lst))
though I'm confused as to how I can rewrite it to not use remove, but rather use a filter.
*note: (f2a '(("a" 1 "b") (2 "c") (-1 "d") (-2))) returns '(("a" "b") ("c") ("d"))
The other two problems are ones to which I haven't found any solutions.
They ask me to write a function that returns a list with all positive odd and negative even integers removed. For example,
(f2b '(("a" 1 "b") (2 "c") (-1 "d") (-2)))
returns
(("a" "b") (2 "c") (-1 "d"))
I have some code down that is incorrect, but I feel shows how I have tried to approach solving this one:
(define (f2b lst)
(lambda(x)
(cond ((and (positive? x) (odd? x)) (filter x lst))
((and (negative? x) (even? x)) (filter x lst))
(else "this should never print"))))
The last problem simply asks for a function that returns a string consisting of all strings appended together in a list. (f2c '(("a" 1 "b") (2 "c") (-1 "d") (-2))) returns "abcd".
I almost managed to figure this one out, but got stuck when it kept returning strange values. This is the code I have:
(define (f2c lst)
(lambda(x)
(map (lambda (x) (filter string? x)) lst)
(list x))
(string-append (car lst) (cdr lst)))
In terms of higher-order syntax, I'm limited to map, filter, accumulate and sum. I am not asking for a direct answer, but rather some help for me to figure out what I need to do. What am I doing wrong with my code? Any assistance given with this is very much appreciated. Thank you.
The structure of the input and the desired output is identical in the first two problems; the only thing that differs is the predicate on when/when-not to remove an element. For the second case it would be:
(define (f2b lst)
(map (lambda (sublst)
(remove (lambda (x)
(and (number? x)
(or (and (positive? x) (odd? x))
(and (negative? x) (even? x)))))
sublst))
lst))
Since only the predicate differs you can generalize this as:
(define (f2x predicate)
(lambda (lst)
(map (lambda (sublst) (remove predicate sublst)) lst)))
(define f2a (f2x number?))
(define f2b (f2x (lambda (x)
(and (number? x)
(or (and (positive? x) (odd? x))
(and (negative? x) (even? x))))))
For your last problem, you can use the result of the first problem as:
(define (f2c lst)
(apply string-append (apply append (f2a list))))
Also, note that your syntax for f2b and f2a is incorrect. You are using
(define (func arg)
(lambda (x) ...))
which means that (func arg) returns a function which isn't what you want.
Put it simply, how to get a list non-repeated letters from a string in Common Lisp?
e.g:
"common"
-> ("c" "o" "m" "n") or in characters, (#\c #\o #\m #\n)
I'd care less about the order and type, if it is in string or character.
"overflow" -> (o v e r f l w)
"tomtomtom" -> (t o m)
etc...
What I was thinking is to collect the first letter of the original string,
Then use the function;
(remove letter string)
collect the first letter of now, removed letter string and append it to the already collected letters from before.
It sounds like recursion but if recursively calling would loose the previously collected *letter*s list, right? I also doubt if there is any built-in functions for this.
Furthermore, I don't want to use set or any of them since I want
to do this completely in functional style.
Thanks for your time.
CL-USER> (remove-duplicates (coerce "common" 'list))
(#\c #\m #\o #\n)
Or you can even do it simply as:
CL-USER> (remove-duplicates "common")
"comn"
There may be certain better possibilities to do that, if you can make some assumptions about the text you are dealing with. For instance, if you are dealing with English text only, then you could implement a very simple hash function (basically, use a bit vector 128 elements long), so that you wouldn't need to even use a hash-table (which is a more complex structure). The code below illustrates the idea.
(defun string-alphabet (input)
(loop with cache =
(coerce (make-array 128
:element-type 'bit
:initial-element 0) 'bit-vector)
with result = (list input)
with head = result
for char across input
for code = (char-code char) do
(when (= (aref cache code) 0)
(setf (aref cache code) 1
(cdr head) (list char)
head (cdr head)))
finally (return (cdr result))))
(string-alphabet "overflow")
;; (#\o #\v #\e #\r #\f #\l #\w)
Coercing to bit-vector isn't really important, but it is easier for debugging (the printed form is more compact) and some implementation may actually optimize it to contain only so many integers that the platform needs to represent so many bits, i.e. in the case of 128 bits length, on a 64 bit platform, it could be as short as 2 or 3 integers long.
Or, you could've also done it like this, using integers:
(defun string-alphabet (input)
(loop with cache = (ash 1 128)
with result = (list input)
with head = result
for char across input
for code = (char-code char) do
(unless (logbitp code cache)
(setf cache (logior cache (ash 1 code))
(cdr head) (list char)
head (cdr head)))
finally (return (cdr result))))
but in this case you would be, in your worst case, create 128 big integers, which is not so expensive after all, but the bit-vector might do better. However, this might give you a hint, for the situation, when you can assume that, for example, only letters of English alphabet are used (in which case it would be possible to use an integer shorter then machine memory word).
Here some code in Haskell, because I am not so familiar with Lisp, but as they're both functional, I don't think, it will be a problem for translating it:
doit :: String -> String
doit [] = []
doit (x:xs) = [x] ++ doit (filter (\y -> x /= y) xs)
So what does it? You've got a String, if it's an empty String (in Haskell [] == ""), you return an empty String.
Otherwise, take the first element and concatenate it to the recursion over the tail of the String, but filter out those elements, which are == first element.
This Function filter is only syntactic sugar for a specific map-function, in Lisp called remove-if as you can reread here: lisp filter out results from list not matching predicate
I have a list of characters (?h ?e ?l ?l ?o) and i want to convert it to string "hello". Currently i use this structure:
(concat (mapcar (lambda (ch) (char-to-string ch)) s))
Is there a more elegant and idiomatic way to convert list of chars to a string in Elisp?
Elisp's concat returns a string:
(concat '(?h ?e ?l ?l ?o))
(Found it out from coerce implementation in cl)
There's also (apply #'string LIST-OF-CHARS).
I want to add a character to a string, and get another string with the character added as a result.
This doesn't work:
(cons \a "abc")
Possible solutions, in order of preference:
Clojure core function
Clojure library function
Clojure user-defined (me!) function (such as (apply str (cons \a "abc")))
java.lang.String methods
Is there any category 1 solution before I roll-my-own?
Edit: this was a pretty dumb question. :(
How about:
(str "abc" \a)
This returns "abca" on my machine.
You can also use it for any number of strings/chars: (str "kl" \m "abc" \a \b).
You could use join from clojure.string:
(clojure.string/join [\a "abc"])
But for the simple use case you should really just use str, as #Dan Filimon suggests. join has the added benefit that you could put a separator between the joined strings, but without a separator it actually just applies str:
(defn ^String join
"Returns a string of all elements in coll, separated by
an optional separator. Like Perl's join."
{:added "1.2"}
([coll]
(apply str coll))
([separator [x & more]]
(loop [sb (StringBuilder. (str x))
more more
sep (str separator)]
(if more
(recur (-> sb (.append sep) (.append (str (first more))))
(next more)
sep)
(str sb)))))