Going over a list of strings to find the string with the needed prefix - racket

I need to define the function plPrefixContained – that consumes 5 strings and
returns the first one that contains the string "pl" as a prefix – if one such
exists, and returns #f otherwise.
What I'm trying to do is to use the prefixes function to go over all the strings in the list and check their prefixes, put them in a new list and to output the first string as the result.
(I will handle the #f case later) my code is down below but it keeps giving me the error-
first: contract violation
expected: (and/c list? (not/c empty?))
given: '()
any help would be appreciated
(: plPrefixContained : String String String String String -> String)
(define (plPrefixContained x y z w v)
(list-ref (prefixes (list x y z w v) '()) 0))
(: prefixes : (Listof String) (Listof String) -> (Listof String))
(define (prefixes lis em)
(cond
[(and (eq? (string-ref (first lis) 0) "p") (eq? (string-ref (first lis) 1) "l"))
(cons (first lis) em)]
[else
(prefixes (rest lis) em)]))
this is how I want my output to be like-for example
(test (plPrefixContained "yypl" "opl" "lpTT" "plpl" "lol")
=>
"plpl")

There are two problems:
intensional equality eq?, instead of extensional equality such as equal? or string=?
comparing string / char, instead of comparing char / char or string / string
You are using eq?, which always makes me suspicious. eq? uses "intensional" equality, which is basically pointer equality, meaning that a string which is allocated somewhere in memory won't necessarily be eq? even if it has the same characters. You can see this with (eq? "abc123" (string-append "abc" "123")).
If you're dealing with strings, lists, or any other data which "contains" things, you should avoid eq?. Instead you should use an "extensional" equality predicate such as equal?, or even better, a predicate specific to the types of values you expect, such as string=?. Here's how they behave better than eq?:
> (eq? "abc123" (string-append "abc" "123"))
#f
> (equal? "abc123" (string-append "abc" "123"))
#t
> (string=? "abc123" (string-append "abc" "123"))
#t
Since you're comparing using the strings "p" and "l", I should be able to substitute eq? with string=? in your code:
(: prefixes : (Listof String) (Listof String) -> (Listof String))
(define (prefixes lis em)
(cond
[(and (string=? (string-ref (first lis) 0) "p") (string=? (string-ref (first lis) 1) "l"))
(cons (first lis) em)]
[else
(prefixes (rest lis) em)]))
However, this reveals the second problem, which I only spotted after seeing the error message:
string=?: contract violation
expected: string?
given: #\y
argument position: 1st
other arguments...:
"p"
The string=? isn't working because its first argument, the result of string-ref, is a character (like #\y), not a string. To fix this, use char=? instead of string=?, and compare with the characters #\p and #\l instead of the strings "p" and "l".
(: prefixes : (Listof String) (Listof String) -> (Listof String))
(define (prefixes lis em)
(cond
[(and (char=? (string-ref (first lis) 0) #\p) (char=? (string-ref (first lis) 1) #\l))
(cons (first lis) em)]
[else
(prefixes (rest lis) em)]))

Related

Alternating upcase/downcase for a string in Common Lisp

I want to write a function that will return a string formatted with alternative upcase/downcase in Common Lisp. For example, entering "stackoverflow" should return the string "StAcKoVeRfLoW". Here's my attempt, but it just returns a list of cons pairs. Am I on the right track?
(defun mockify (chars)
(let ((lst (coerce chars 'list)))
(if (equal lst nil) nil
(coerce (cons
(cons (char-upcase (car lst)) (char-downcase (cadr lst)))
(mockify (cddr lst)))
'string))))
CL-USER> (mockify "meow")
((#\M . #\e) (#\O . #\w))
Using MAP: we are creating a new string, moving over the original string and upcase/downcase based on an alternating boolean variable.
CL-USER 353 > (let ((string "stackoverflow")
(upcase t))
(map (type-of string)
(lambda (element)
(prog1 (if upcase
(char-upcase element)
(char-downcase element))
(setf upcase (not upcase))))
string))
"StAcKoVeRfLoW"
(defun mockify (chars)
(let ((lst (coerce chars 'list)))
(if (equal lst nil)
;; return nil
nil
;; return a string (coerce)
(coerce
;; a list whose elements are cons-cells, but ...
(cons (cons (char-upcase (car lst))
(char-downcase (cadr lst)))
;; ... the rest is computed by calling mockify,
;; which returns either an empty list or a string
(mockify (cddr lst)))
'string))))
The types of your expressions are confusing, and in fact your example leads to an error when using SBCL:
> (mockify "meow")
The value
(#\O . #\w)
is not of type
CHARACTER
when setting an element of (ARRAY CHARACTER)
[Condition of type TYPE-ERROR]
Also, you are going to have to handle corner cases in your code, because as is, it is possible that (cadr list), i.e. (second list), is called on a list that has only one element. Then, the result would be NIL and char-downcase would fail with an error.
Using only strings
I'd suggest writing a version of the function that does not use intermediate lists:
let R be the string-downcase of the whole string
then modify every other character of R by upcasing it
So for example, one way to do it (among others) would be:
(defun mockify (chars)
(let ((chars (string-downcase chars)))
(prog1 chars
(upcasify chars 0))))
(defun upcasify (string index)
(when (< index (length string))
(setf (char string index) (char-upcase (char string index)))
(upcasify string (+ index 2))))
Using only lists
If you prefer having a recursive function that processes lists, I'd rather define it in layers:
coerce string to list
process the list recursively
eventually, coerce the resulting list back to a string
This will avoid doing conversions from strings to lists at every step, and make the code simpler at each level.
(defun mockify (chars)
(coerce (mockify-list (coerce chars 'list)) 'string))
(defun mockify-list (chars)
...)
The list version is recursive and look like what you tried to do, but take care of corner cases.
There is more than one way to do it. Here is a loop based solution:
(let ((string "StackOverflow"))
(with-output-to-string (s)
(loop :for c :across string
:for up := t :then (not up)
:do (princ (if up
(char-upcase c)
(char-downcase c))
s))))
Fun thing - I actually wrote a similar thing some time ago.
https://github.com/phoe/string-pokemonize

Switch uppercase and lowercase of a string

I'm doing a question where it asks me to convert all uppercases in a string to lowercases and lowercases to uppercases, and all other characters remain the same.
Below is my code:
(define (switch-case str)
(list->string
(cons
(cond
[(char-lower-case? (first (string->list str))) (char-upcase (first
(string->list str)))]
[(char-upper-case? (first (string->list str))) (char-downcase (first
(string->list str)))]
[else (first (string->list str))])
(switch-case (rest (string->list str))))))
The error message for str "ABC" is:
string->list: expects a string, given (cons #\B (cons #\C empty))
Can somebody tell me what has gone wrong with my code? Thx
The recursive call is on the wrong type. You pass [List-of Character] to switch-case, but it expects String.
; String -> String
(define (switch-case str)
(list->string
(cons
(swapcase nestr)
(switch-case
(rest (string->list str)) ; the type of this expression is [List-of Character]
))))
Follow this template:
; [List-of Character] -> [List-of Character]
(define (switch-case-charlist cl)
(cond [(empty? cl) ...]
[else (... (first cl) ... (switch-case-charlist (rest cl)))]))
; Character -> Character
(define (swap-case-character c)
...)
; String -> String
(define (swap-case-string s)
(list->string (... (string->list s))))

I am new to Racket and need some help for this function

I want the answer to be #t here:
> (is-member? "foo" '(4 5 #f "foo" a))
#t
But I'm getting the error:
> (is-member? "foo" '(4 5 #f "foo" a))
;string=?: contract violation
; expected: string?
; given: #f
; argument position: 2nd
; other arguments...:
; "foo"
My definitions of is-member? and is-member-string? are:
#lang racket
(define (is-member? num lst)
(if (null? lst)
#f
(if (string? num)
(is-member-string? num lst)
(is-member-number? num lst))))
(define (is-member-string? num lst)
(if (null? lst)
#f
(if (integer? (car lst))
(is-member-string? num (rest lst))
(if (string=? (car lst) num)
#t
(is-member-string? num (rest lst))))))
(define (is-member-number? num lst)
....)
Look at the error message and see how it helps you. It says the error is coming from string=?, and if you look in DrRacket it even highlights the specific call that went wrong. It's the (string=? (car lst) num) in the is-member-string? function.
Figure out what arguments were and why they're wrong. The error message says that the wrong argument was #f where it expected a string.
Where did the bad argument come from? Was it num or (car lst)? Looking at how num flows through the program, num should always be "foo", so it's probably the other one, (car lst).
How did this code execute with that bad argument? Why is (car lst) false here? Because it's walking down the list, and the list contains a false in it. That should be fine, as long as you design your function properly to handle all values.
To do that, you should put a type signature on your functions to show what types of arguments are allowed. For is-member-string? I'm assuming you meant:
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
....)
(I've renamed num to str because it's not a number, it's a string.)
Next you need to make sure that the code works with the signature. You're designing this function by destructuring the list argument, but you need to keep the types of the values in mind:
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
(if (null? lst)
#f
(.... (first lst) ; (first lst) is an Any
.... (rest lst)))) ; (rest lst) is a [List-of Any]
(I'm using first instead of car because first makes more sense.)
Can you see what's wrong now?
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
(if (null? lst)
#f
(if (integer? (first lst)) ; (first lst) is an Any
(is-member-string? str (rest lst))
(if (string=? (first lst) str) ; (first lst) is an Any, but not an integer
#t
(is-member-string? str (rest lst))))))
(first lst) is an Any, but you're using (string=? (first lst) str). That shouldn't be allowed unless you're sure that (first lst) is a string.
There are two ways to do this. One way to fix this is to use (equal? (first lst) str) instead.
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
(if (null? lst)
#f
(if (equal? (first lst) str)
#t
(is-member-string? str (rest lst)))))
The second way is to check that it's a string before you use string=?. I assume that's what you were trying to do with your integer? check, but it isn't working. Instead you want to use (string? (first lst)) somehow. You only want to check string=? after that passes. One way to do that is with and.
;; is-member-string? : String [List-of Any] -> Boolean
(define (is-member-string? str lst)
(if (null? lst)
#f
(if (and (string? (first lst)) (string=? (first lst) str))
#t
(is-member-string? str (rest lst)))))

Defining a function that accepts a List of Lists in racket

My assignment is to count how many lists I have with length 3 in my list (List of List).
I thought I built everything correctly, but when I want to send the first list to my recursive function it fails because my list has the type Any, and I can't find a way to make it a list of lists.
#lang pl
(: count-3lists : (Listof Any) -> Number)
(define (count-3lists l)
(cond
[(null? l) 0]
[else (+ (count-3lists-helper (first l)) (count-3lists (rest l)))]))
(: count-3lists-helper : (Listof Any) -> Number)
(define (count-3lists-helper l)
(cond [(= (length l) 3) 1]
[else 0]))
(: length : (Listof Any) -> Number)
(define (length l)
(cond
[(null? l) 0]
[else (add1 (length (rest l)))]))
The error I get is:
. Type Checker: Polymorphic function `first' could not be applied to
arguments:
Types: (Pairof a (Listof b)) -> (a : ((! False # (car) (0 0)) | (False # (car) (0 0))) : (car (0 0)))
(Listof a) -> a
Arguments: (Pairof Any (Listof Any))
Expected result: (Listof Any)
in: (first l)
It seems like you want your count-3lists function to take a list of lists as its input. Right now you have (Listof Any).
What you want is express something like (Listof List), but the inner list has to be a list of something, so you can write that as (Listof (Listof Any)).
Then the first part of your code becomes this:
(: count-3lists : (Listof (Listof Any)) -> Number)
(define (count-3lists l)
(cond
[(null? l) 0]
[else (+ (count-3lists-helper (first l)) (count-3lists (rest l)))]))
After that, the rest of your code works. It turns out that your length function was fine. (So you should probably rename your question.)

Lisp - Remove instances from a list of pairs

I want to create a function in lisp that receives a number and a list of pairs and iterates through the list of pairs and removes the ones in which the result of the division between the first element of the pair, and the second element of the same pair is different from the number passed as an argument. In the end it returns a list with only the ones in which the result of the division is the same.
I have the following code so far:
(defun retira-terco(num l1)
(cond ((null l1) ())
((not (equal num (/ (car(first l1)) (cdr(first l1)))))
(retira-terco num (rest l1)))
(t (cons (first l1) (retira-terco num (rest l1))))))
When I try to run this example with a real example I get the following error:
Error: `(1)' is not of the expected type `NUMBER'
What am I doing wrong?
The problem with your code is in this line:
(/ (car(first l1)) (cdr(first l1)))
(car (first l1)) evaluates to a number, but (cdr (first l1)) evaluates to a list. You probably meant (cadr (first l1)).
That said, this code isn't that great from a lispiness point of view. You have a condition you want to filter on. Use higher order programming to express that more like this:
(defun foo (num lst)
(remove-if (lambda (item)
(equal num
(/ (car item)
(cadr item))))
lst)))