How do I Extract the First character of a symbol in scheme? - scheme

I want it to extract all the words that have a letter e in them.
eg.
(ewords '(i e ee o oo)) -> '(e ee)
Berkeley's 61a lecture uses (first 'word) to extract the first character of the word. However DrScheme screams at me when I try to do that. How do take the first character of the word? like
(first 'word)->'w.

You'll need to convert it to a string explicitly:
(first (symbol->string 'word)) -> "w"
(I'm not sure off the top of my head whether first operates on strings. You can use string->list to convert to a list and then take the first if it doesn't.)
EDIT: It might be easier to pass around strings instead of symbols in the first place -- to designate a string, use double quotes (e.g. (ewords '("i" "e" "ee" "o" "oo")).) I don't know if this is your intent, but since you're learning, I thought I should mention the distinction.

Symbols are primarily meant to be atomic values, i.e., they are not usually taken apart and examined. If you really want to do it you must first do some type conversions:
; #\a -> a
(define (char->symbol chr)
(string->symbol (list->string (list chr))))
; abc -> (a b c)
(define (symbol->list sym)
(map char->symbol
(string->list (symbol->string sym))))
You can now use first:
> (first (symbol->list 'word))
w

It depends, what is the data definition for a "word"?
Is it a sequence of characters (aka a string)? Is it a list of characters? A list of strings? A list of symbols?
Here is a function that meets your criteria, but as you can see, it is convoluted and I wonder if it is what you really want:
; symbol->list-of-symbols : symbol -> (ListOf symbol)
; To destructure a symbol into a list of its constituent parts
(define (symbol->list-of-symbols sym)
(map (lambda (s) (string->symbol (string s)))
(string->list (symbol->string sym))))

Related

What does underscore stand for in this code

How does following code work? This code is from Racket documentation https://docs.racket-lang.org/plot/renderer2d.html?q=2d%20renderers#%28part.2.D.Line_.Renderers%29 (see function points on this page). This is not usual function definition statement. What does the underscore stand for here?
(define xs (build-list 5 (λ _ (random))))
The xs gets following value:
> xs
'(0.9520057193043618 0.1339193598495859 0.0019128879992944899 0.7511052254656998 0.4442323053722083)
A lambda can either have a list of identifiers as parameter names (such as (lambda (a b c) the-body )) or a single identifier (such as (lambda args the-body), which will then hold the list of all arguments.
The function given to build-list takes one parameter (the current index). It is customary to name parameters _ when you don't intend to use their value.
So since we don't care about the current index when creating a random list, the parameter is named _. This could also be written as (lambda (_), but since we don't care about any of the (one) parameters, we can just write (lambda _ as well.

case and quotation in scheme & racket

I was a bit surprised by this racket code printing nay when I expected yeah:
(define five 5)
(case 5
[(five) "yeah"]
[else "nay"])
Looking at the racket documentation for case makes it clearer:
The selected clause is the first one with a datum whose quoted form is equal? to the result of val-expr.
So it's about quotation. I'm pretty sure that I did not yet fully grasp what quotation in lisps can buy me. I understand it in the viewpoint of macros and AST transformation. However I'm confused why is it helpful in the case of case for instance..?
I'm also curious, with this specification of case, can I use it to achieve what I wanted to (compare the actual values, not the quoted value), or should I use another construct for that? (cond, while strictly more powerful, is more verbose for simple cases, since you must repeat the predicate at each condition).
The problem is that case introduces implicit quote forms, which cause your example to work for 'five (whose value is 'five), instead of five (whose value is 5).
I almost never use case because of exactly this problem. Instead I use racket's match form with the == pattern:
(define five 5)
(define (f x)
(match x
[(== five) "yeah"]
[_ "nay"]))
(f 5) ; "yeah"
(f 6) ; "nay"
This produces "yeah" on only the value 5, just like you expected. If you wanted it to return "yeah" when it's equal to either five or six, you can use an or pattern:
(define five 5)
(define six 6)
(define (f x)
(match x
[(or (== five) (== six)) "yeah"]
[_ "nay"]))
(f 5) ; "yeah"
(f 6) ; "yeah"
(f 7) ; "nay"
And if you really want to match against quoted datums, you can do that by writing an explicit quote form.
(define (f x)
(match x
[(or 'five 'six) "yeah"]
[_ "nay"]))
(f 5) ; "nay"
(f 6) ; "nay"
(f 7) ; "nay"
(f 'five) ; "yeah"
(f 'six) ; "yeah"
These quote forms are implicit and invisible when you use case, lurking there waiting to cause confusion.
The Racket documentation gives this grammar:
(case val-expr case-clause ...)
where
case-clause = [(datum ...) then-body ...+]
| [else then-body ...+]
Let's compare to your example:
(define five 5)
(case 5 ; (case val-expr
[(five) "yeah"] ; [(datum) then-body1]
[else "nay"]) ; [else then-body2])
We see that (five) is interpreted as (datum). This means that five is
a piece of data (here a symbol), not an expression (later to be evaluated).
Your example of case is evaluated like this:
First the expression 5 is evaluated. The result is the value 5.
Now we look at a clause at a time. The first clause is [(five) "yeah"].
Is the value 5 equal (in the sense of equal?) to one of the datums in (five)? No, so we look at the next clause: [else "nay"]. It is an else-clause so the expression "nay" is evaluated and the result is the value "nay".
The result of the case-expression is thus the value "nay".
Note 1: The left-hand sides of case-clauses are datums (think: they are implicitly quoted).
Note 2: The result of val-expr is compared to the clause datums using equal?. (This is in contrast to Scheme, which uses eqv?.
UPDATE
Why include case? Let's see how one can write the example using cond:
(define five 5)
(let ([val five])
(cond
[(member val '(five)) "yeah"]
[(member val '(six seven)) "yeah"] ; added
[else "nay"])
This shows that one could do without case and just use cond.
However - which version is easier to read?
For a case expression it is easy to see which datums the value is compared to.
Here one must look closely to find the datums. Also in the example we know beforehand that we are trying to find the value among a few list of datums. In general we need to examine a cond-expression more closely to see that's what's happening.
In short: having a case-expression increases readability of your code.
For the historically interested: https://groups.csail.mit.edu/mac/ftpdir/scheme-mail/HTML/rrrs-1986/msg00080.html disussed whether to use eqv? or equal? for case.
UPDATE 2
I'll attempt to given an answer to:
I'm still not clear on the quotation vs working simply on the values though.
I'm wondering specifically why doing the quotation, why working on datum instead
of working on values. Didn't get that bit yet.
Both approaches make sense.
Let's for the sake of argument look at the case where case uses expressions rather than datums in the left hand side of a clause. Also following the Scheme tradition, let's assume eqv? is used for the comparison. Let's call such a
case-expression for ecase (short for expression-case).
The grammar becomes:
(ecase val-expr ecase-clause ...)
where
ecase-clause = [(expr ...) then-body ...+]
| [else then-body ...+]
Your example now becomes:
(define five 5)
(ecase five
[('five) "yeah"]
[else "nay")
This doesn't look too bad and the result is what we are used to.
However consider this example:
(ecase '(3 4)
[('five (list 3 4) "yeah"]
[else "nay")
The result of this would be "nay". The two lists resulting from evaluating the expressions '(3 4) and (list 3 4) are not equal in the sense of eqv?.
This shows that if one chooses to use eqv? for comparisions, having expressions available on the left hand side won't be helpful. The only values that work with eqv? atomic values - and therefore one could just as well use implicit quotations and restrict the left hand side to datums.
Now if equal? was used it would make much more sense to use expressions on the left hand side. The original Racket version of case was the same as the one in Scheme (i.e. it used eq?) later on it was changed to used equal?. If case was designed from scratch, I think, expressions would be allowed rather than datums.
The only remaining issue: Why did the authors of Scheme choose eqv? over equal? for comparisons? My intuition is that the reason were performance (which back in the day was more important than now). The linked to post from the rrrs-authors mailing list gives two options. If you dig a little further you might be able to find responses.
I can't find a reference right now, but case statements use literal, unevaluated data in their different clauses because it is both a frequent use-case and more easily subject to efficient compilation.
You could probably write your own version of Clojure's condp macro or a custom conditional operator to handle your use case.

Lisp format list with parameter

I'm trying to create a function that will take a string and display it.
(defun closing (s)
(format t "~{~a~}" ("Sincerely," "\n" s)))
What I hope to get is
Sincerely,
Frank
if "Frank" is the string I passed in. It complains of the variable S is defined but never used. What am I doing wrong?
Trying to use format alone: If I declare urname as a defparameter to be "Frank", the following doesn't print Frank, rather just the variable name. (Without quote it complains of urname not being a function.)
(format t "~{~a~}" '(urname urname urname))
How can I feed variables to format?
There are three issues here: (1) The code you posted doesn't just have the problem of not using s; it's also trying to call the string "Sincerely" as a function; (2) quoting a list means you'll get exactly what's quoted (e.g., a list of symbols, not a list of values of variables); (3) calling format with lists.
(something other-stuff...) is a function call
When I put the code you posted into SBCL, I get some very specific and helpful output:
CL-USER> (defun closing (s)
(format t "~{~a~}" ("Sincerely," "\n" s)))
; in: DEFUN CLOSING
; ("Sincerely," "n" S)
;
; caught ERROR:
; illegal function call
; (SB-INT:NAMED-LAMBDA CLOSING
; (S)
; (BLOCK CLOSING (FORMAT T "~{~a~}" ("Sincerely," "n" S))))
;
; caught STYLE-WARNING:
; The variable S is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 1 STYLE-WARNING condition
("Sincerely," "\n" s) is an illegal function call, since a string, like "Sincerely", can't have a function binding. Since SBCL sees the problem in that, it recognizes that the one thing that s might have been used for (i.e., an argument to a function call), can't happen. That's why you'll get the error, and then the associated style warning.
Creating lists of values
The second is probably answered in other questions already, but the short answer is that you want (list x y z), not '(x y z). The former calls the function list with the values of the variables x, y, and z, while the latter denotes a literal list of the symbols x, y, and z.
CL-USER> (let ((a 42)
(b 89))
(print '(a b)) ; a list of two symbols
(print (list a b))) ; a list of two numbers
(A B)
(42 89)
Format, iteration, &c.
The third is probably more interesting, since format has so many possibilities. The ~{ and ~} in your example are used for iterating over values in a list. First, let's look at a simple example: you can just use the format directive ~a and call format with the arguments you want to splice in:
CL-USER> (let ((closing "Sincerely")
(name "Frank"))
(format t "~a,~%~a" closing name))
Sincerely,
Frank
Now, if you need to print multiple values, you can use ~{ and ~} to have format iterate over a list of values:
CL-USER> (let ((closing "Sincerely")
(names '("Frank" "John")))
(format t "~a,~{~%~a~}" closing names))
Sincerely,
Frank
John
If the names are the values of variables, then you can either create a list containing those values:
CL-USER> (let ((closing "Sincerely")
(name1 "Frank")
(name2 "John"))
(format t "~a,~{~%~a~}" closing (list name1 name2)))
Sincerely,
Frank
John
or you can change ~{ to ~#{ and have format read the remaining arguments as the list:
CL-USER> (let ((closing "Sincerely")
(name1 "Frank")
(name2 "John"))
(format t "~a,~#{~%~a~}" closing name1 name2))
Sincerely,
Frank
John
You should read a tutorial about format, from here for example
For an easy explanation
(format
(destination-stream usually t for standard output nil to form a string)
(here comes the string)
(&rest variables that should write in the string where is an ~A and by position like String.format in java or c))
in your case, you need the symbol ~% or use the character for return in common lisp
CL-USER> (defun closing (s) (format t "~A~%~%~A" "Sincerely," s))
CLOSING
CL-USER> (closing "paco")
Sincerely,
paco
NIL
The nil say that the functions returns null, and the other is the standard output if you want to return a string, put nil instead of t

scheme function checking constants/vowels

How to create a function in Dr. Racket consumes a string str and produces true if str has at least a vowel and false if str has no vowels.
The vowels are the following set of characters: A, a, E, e, I, i, O, o, U, u.
For example:
(has-vowel? "whatever") => true
(has-vowel? "trythnks") => false
#ÓscarLópez
This is what I have come up with so far. THe function can whether the first letter is a vowel or not. My problem now is, how do I get the function to check the other letters?
I keep getting this error in Scheme (rest: expects a non-empty list; given "string")
I'm don't know exactly how to fix it. Any help/suggestions is most welcome. Thanks.
This looks like homework, so I'll give you some hints to get started. First, let's split the problem in two procedures - the first one will transform the string into a list of characters, and will also define the list of characters we're looking for. Fill-in the blanks:
(define (has-vowel? str)
(any-in-list ; helper procedure, we'll get to this later
(<???> str) ; how to transform a string into a list of chars?
'(#\A #\a <???>))) ; list of vowels
With the above procedure in place, we can write our helper procedure, any-in-list. It's a general solution for determining if any of the elements in one list is in the other - think about it as a predicate that tells if the intersection of two lists is non-empty:
(define (any-in-list lst check)
(cond (<???> <???>) ; if lst is empty, we didn't find any element, return #f
(<???> #t) ; return #t if the first element in lst is in check
(else (any-in-list <???> check)))) ; else advance the recursion over lst
The tricky part is in the second line of any-in-list. How do we determine if an element is in another list? we could write another helper procedure for this, but a quick look at the documentation will get you right on track. And don't forget to test your code, this should work as expected:
(has-vowel? "whatever")
=> #t
(has-vowel? "trythnks")
=> #f
One solution would be to:
convert the string to a list of characters (string->list)
Iterate over the list and check for vowel characters (characters)

Scheme: Combining random and substring

I am trying to create a procedure that has a user input a non-empty string and then returns a random letter from the input in a substring of length one.
i.e.
(pick-at-random "word")
~"w"
(pick-at-random "word")
~"r"
So far I've got:
(define pick-at-random
(lambda (s)
(substring s (random(string-length s)) ())))
This gives me the position of the letter I want to display and I feel like where the () is, I should have some variable representing the start value of the substring and then add one to it. However, I don't know how to do this. Simply put, I am asking how I can limit the substring to length one while using the random function in the start value.
You may use let to bind the random number to a variable.
(define pick-at-random
(lambda (s)
(let ((index (random (string-length s))))
(substring s index (+ index 1)))))
Here's an alternative answer without using substring, in this way you don't need to save the index in a let binding. It's a more functional (and hence, idiomatic) solution to the problem:
(define (pick-at-random s) ; read the following lines from bottom to top
(string ; convert single character to string
(string-ref s ; access character in string, given an index
(random (string-length s))))) ; generate a random valid index in the string
(pick-at-random "word")
> "d" ; random result
The previous procedure generates a random valid index and then picks the character in that position within the string. As the last step, it turns back the single character into a string of length one.
The prior two answers are fine. Alternatively, you could break this problem into two problems:
Develop the function "nth-char" that accepts a word and an index, and returns a string containing the nth character of the word.
Develop the function "pick-at-random" that does what you describe. (Incidentally, I think a name such as "random-char" is somewhat better than "pick-at-random".)
This decomposition solves the problem you describe, by making it an argument to another function.
"Under the hood", this is the same solution as the one that uses "let".

Resources