Switch statement in Lisp - switch-statement

Switch statement with Strings in Lisp.
(defun switch(value)
(case value
(("XY") (print "XY"))
(("AB") (print "AB"))
)
)
I want to compare if value is "XY" then print "XY" or same for "AB".
I have tried this code but it gives me nil. Can some please tell me what i am doing wrong?

You can use the library alexandria, which has a configurable switch macro:
(switch ("XY" :test 'equal)
("XY" "an X and a Y")
("AB" "an A and a B"))

print("XY") looks more like Algol (and all of its descendants) rather than LISP. To apply print one would surround the operator and arguments in parentheses like (print "XY")
case happens to be a macro and you can test the result yourself with passing the quoted code to macroexpand and in my implementation I get:
(let ((value value))
(cond ((eql value '"XY") (print "XY"))
((eql value '"AB") (print "AB"))))
You should know that eql is only good for primiitive data types and numbers. Strings are sequences and thus (eql "XY" "XY") ;==> nil
Perhaps you should use something else than case. eg. use cond or if with equal.

The Hyperspec on CASE says:
These macros allow the conditional execution of a body of forms in a clause that is selected by matching the test-key on the basis of its identity.
And strings are not identical in CL, i.e. (EQ "AB" "AB") => NIL.
That is why CASE wouldn't work for strings. You either need to use symbols (they are interned once only, thus guaranteeing identity) or use COND with EQUAL or even EQUALP if the letters case to be ignored.

Related

how to retrieve a key in a map whose value contains a particular substring in clojure?

i need to retrieve the key whose value contains a string "TRY"
:CAB "NAB/TRY/FIGHT.jar"
so in this case the output should be :CAB .
I am new to Clojure, I tried a few things like .contains etc but I could not form the exact function for the above problem.its easier in few other languages like python but I don't know how to do it in Clojure.
Is there a way to retrieve the name of the key ?
for can also filter with :when. E.g.
(for [[k v] {:FOO "TRY" :BAR "BAZ"}
:when (.contains v "TRY")]
k)
First, using .contains is not recommended - first, you are using the internals of the underlying language (Java or JavaScript) without need, and second, it forces Clojure to do a reflection as it cannot be sure that the argument is a string.
It's better to use clojure.string/includes? instead.
Several working solutions have been already proposed here for extracting a key depending on the value, here is one more, that uses the keep function:
(require '[clojure.string :as cs])
(keep (fn [[k v]] (when (cs/includes? v "TRY") k))
{:CAB "NAB/TRY/FIGHT.jar" :BLAH "NOWAY.jar"}) ; => (:CAB)
The easiest way is to use the contains method from java.lang.String. I'd use that to map valid keys, and then filter to remove all nil values:
(filter some?
(map (fn [[k v]] (when (.contains v "TRY") k))
{:CAB "NAB/TRY/FIGHT.jar" :BLAH "NOWAY.jar"}))
=> (:CAB)
If you think there is at most one such matching k/v pair in the map, then you can just call first on that to get the relevant key.
You can also use a regular expression instead of .contains, e.g.
(fn [[k v]] (when (re-find #"TRY" v) k))
You can use some on your collection, some will operate in every value in your map a given function until the function returns a non nil value.
We're gonna use the function
(fn [[key value]] (when (.contains values "TRY") key))
when returns nil unless the condition is matched so it will work perfectly for our use case. We're using destructuring in the arguments of the function to get the key and value. When used by some, your collection will indeed be converted to a coll which will look like
'((:BAR "NAB/TRY/FIGHT.jar"))
If your map is named coll, the following code will do the trick
(some
(fn [[key value]] (when (.contains value "TRY") key))
coll)

How to convert a list of strings to symbols in elisp

The high-level goal is to use org-mode for handling package configuration using the pretty formatted lists which is passed in as a list of strings. package-installed-p and package-install both take symbols though.
i.e: with company installed
(if (package-installed-p 'company)
(print "yes")
(print "no"))
would output "yes"
Then from a string
(if (package-installed-p (intern "company"))
(print "yes")
(print "no"))
still outputs "yes"
It seems like I should be able to
(mapcar 'intern company)
to get a list of symbols defined from the strings in the list.
Instead, I get the error: 'Wrong type argument: stringp, ("company")'
The issue is that the string is wrapped inside a container.
(mapcar (lambda (x) (intern (car x))) packages)
appears to do the trick.

Strange comparison of `'quote` and `'lambda` in Scheme (guile)

Let see my code
Code1:
(eqv? 'lambda 'quote)
return #f
Code2:
(case 'lambda ('quote "equal") (else "not equal"))
return "not equal" but generate a warning ;;; <stdin>:17:0: warning: duplicate datum quote in clause ((quote quote) "equal") of case expression (case (quote lambda) ((quote quote) "equal") (else "not equal"))
Code3: strange result
(case 'quote ('lambda "equal"))
return "equal" and without warning
I interpreted code using guile (GNU Guile) 2.0.11. And here is the description of case syntax from gnu
The the result of this evaluation is compared against all datums using eqv?
'<something> is an abbreviation for the list (quote <something>). In Scheme, the case form should be a list (in some Lisps, e.g., Common Lisp, it can also be a single non-list element, representing the list of just that element), so that you can do, e.g.:
(case n
((0) 'zero) ; in Common Lisp, could also be (0 'zero)
((1 2 3) 'one-two-or-three)
((4 5) 'four-or-five))
When you do:
(case some-symbol
('quote 'it-was-quote))
You're doing
(case some-symbol
((quote quote) 'it-was-quote))
So you're providing a list, and it's got a duplicate element. There's nothing wrong with that, but it's usually unexpected, and so you get a warning.
By that reasoning
(case 'quote ('lambda "equal"))
is the same as
(case 'quote ((quote lambda) "equal"))
and, since the symbol quote is in the list (quote lambda), the case matches, and you get "equal". The moral of the story is: "don't quote the cases in case." That is, you should be doing:
(case 'quote
((lambda) "equal"))

Importing strings to Scheme without using open-input-string

I am trying to have my Scheme program import strings without needing to use open-input-string before the string. So for example, right now I can do the following:
> (scheme_lexer (open-input-string "3+4*2"))
However, is there a way for my program to work if I input the string this way?:
> (scheme_lexer ("3+4*2"))
Thank you!
Is there any particular reason you can't just make a scheme_lexer_string function that does this for you when dealing with strings? The extra parentheses just seem like clutter, and they make a macro the only real solution. If you dropped that requirement and made something like (scheme_lexer "3+4*2") acceptable, you can make an ordinary function for handling strings:
(define (scheme_lexer_string s)
(scheme_lexer (open-input-string s)))
If what you want is a function that handles both input ports and strings, you can make a general function that dispatches based on the type of the argument to the specific functions. In this case, your original scheme_lexer would be renamed to scheme_lexer_input_port and you would have these functions:
(define (scheme_lexer_string s)
(scheme_lexer_input_port (open-input-string s)))
(define (scheme_lexer in)
(if (string? in)
(scheme_lexer_string in)
(scheme_lexer_input_port in)))
Now scheme_lexer works for both strings and ports and dispatches to the correct function as desired.
> (scheme_lexer some-input-port)
... evaluates the content in the port
> (scheme_lexer "abcd")
... evaluates the string "abcd"
Here is one option. I have used a testing function lexer just to show the macro. You can adjust it to your needs.
(define (lexer sp) (read sp))
(define-syntax scheme_lexer
(syntax-rules ()
((_ (input))
(lexer (open-input-string input)))))
And to test:
> (scheme_lexer ("3+4*2"))
'3+4*2

Which is the most clojuresque way to compare characters and string? (single char string)

I was wondering about which is the best (clojuresque) way to compare a character and a string in Clojure.
Obviously something like that returns false:
(= (first "clojure") "c")
because first returns a java.lang.Character and "c" is a single character string. Does exists a construct to compare directly char and string without invoking a cast? I haven't found a way different from this:
(= (str (first "clojure")) "c")
but I'm not satisfied.
Any ideas?
Bye,
Alfredo
How about the straight forward String interop?
(= (.charAt "clojure" 0) \c)
or
(.startsWith "clojure" "c")
It should be as fast as it can get and doesn't allocate a seq object (and in your second example an additional string) which is immediately thrown away again just to do a comparison.
Character literals are written \a \b \c ... in Clojure so you can simply write
(= (first "clojure") \c)
strings can be directly indexed without building a sequence from then and taking the first of that sequence.
(= (nth "clojure" 0) \c)
=> true
nth calls through to this java code:
static public Object nth(Object coll, int n){
if(coll instanceof Indexed)
return ((Indexed) coll).nth(n); <-------
return nthFrom(Util.ret1(coll, coll = null), n);
}
which efficiently reads the character directly.
first call through to this java code:
static public Object first(Object x){
if(x instanceof ISeq)
return ((ISeq) x).first();
ISeq seq = seq(x); <----- (1)
if(seq == null)
return null;
return seq.first(); <------ (2)
}
which builds a seq for the string (1) (building a seq is really fast) and then takes the first item from that seq (2). after the return the seq is garbage.
Seqs are clearly the most idomatic way of accessing anything sequential in clojure and I'm not knocking them at all. It is interesting to be aware of what you are creating when. switching out all your calls to first with calls to nth is likely to be a case of premature optimization. if you want the 100th char in the string i would suggest using an indexed access function like nth
in short: don't sweat the small stuff :)
Fundamentally (at least on the Clojure level — though see Kotarak's answer and others for alternatives to this), you're comparing two sequences: "clojure" and "c". The condition of equality is that the first element of each sequence is equal. So if you want to express this directly you can do
(apply = (map first ["clojure" "c"]))
or the other way around, where you create a lazy sequence over the equality comparison between each pair of characters, and just take the first element of it:
(first (map = "clojure" "c"))
You could use the take function from clojure.contrib.string. Or write your own function that returns the first char if that's something you need frequently.
You can just use str, as you did in your second example. There isn't really anything wrong with that. I mean, you could call first on "c" as well to make it a character, but it wont really make a difference. Is there any reason why you don't like this? It's not really adding much to your code by calling str on the character.
user=> (= (subs "clojure" 0 1) "c")
true
user=> (= (str (first "clojure") "c"))
true
These days you don't necessarily have to use Java interop:
(clojure.string/starts-with? "clojure" "c")
starts-with? is just a thin wrapper (around .startsWith).
So now if you use both Clojure and ClojureScript you won't have to remember both the Java and the JavaScript interop.

Resources