Racket function recursion - racket

hello I'm a student currently trying to make a function in Dr racket that's purpose is
when a letter is selected it turns it into underscore
string(word) string(letter) -> string(answer/underscore)
I've only been able to make this happen with one letter as _ which makes the second check true and I can't figure out how to do multiple letters
(check-expect(underscore "william""li")"_illi__"))
(check-expect(underscore "william" "l")"__ll___))
My code:
(define (anti-omit word letter)
(cond[(string=? word letter)letter]
[(= 1 (string-length word))"_"]
[else
(string-append
(anti-omit (substring word 0 1)letter)
(anti-omit (substring word 1)letter))]))

Here's a stub with a purpose statement, signature, and your tests:
;; String String -> String
;; keeps all letters that occur in l, replaces with "_" otherwise
(check-expect (anti-omit "william" "li") "_illi__")
(check-expect (anti-omit "william" "l") "__ll___")
(define (anti-omit w l)
"")
Since you're using a student language, and as you suggest in the title of the question that you want to recur on the data... you'll need a recursive data-definition:
;; String is one of:
;; - ""
;; - (string-append 1String String)
Complete the definition of this function:
;; String -> String
;; is str equal to "" ?
(define (string-empty? str)
...)
a more restrictive data-definition for other two functions (which correspond to rest and first of a list):
;; NEString is one of:
;; - (string-append 1String "")
;; - (string-append 1String NEString)
Some other functions for you to complete:
;; NEString -> String
;; remove the first 1String from str
(define (string-rest str)
...)
;; NEString -> String
;; the first 1String form str
(define (string-first str)
...)
Now you can make functions like this on Strings:
;; [1String -> 1String] String -> String
;; Applies the function f on each 1String in s
(define (map-str f s)
(cond [(string-empty? s) ""]
[else (string-append (f (string-first s)) (map-str f (string-rest s)))]))
Similarly, complete this definition:
;; 1String String -> Boolean
;; is does 1String occur in String?
(define (member-str e l)
...)
Our "wish list" is complete, and we can compose our helpers to finish the final function:
(define (anti-omit w l)
(map-str (λ (x) (if (member-str x l) x "_")) w))
A similar version that uses explode and implode and doesn't need any of the functions we defined (use this as a reference implementation):
(define (anti-omit-ref w l)
(implode (map (λ (x) (if (member? x (explode l)) x "_")) (explode w))))

Related

a Racket problem about the accumulator-style recursion

Using accumulator-style recursion, write a function
one-long-string that consumes a ListOfString and produces the
concatenation of strings in the list in the order they appear in the list.
That is, (one-long-string (list "Alice" "Bob" "Eve")
returns "AliceBobEve"
Notes (added later):
Original question (quoted below) did not specify a particular Racket language, or provide an
attempted solution, or indicate what sort of issue prompted the question.
This answer will use Racket's Beginning Student
language (BSL), and develop (in exhaustive detail) a simple "natural recursion" solution, followed by
conversion to the requested "accumulator-style". BSL is used to focus attention on how using the design method
enables solution development without requiring "leaps of intuition", or familiarity with advanced language.
Readers may wonder how long it actually takes, meticulously following the design recipe with it's
signatures, check-expect tests, template copying and editing, etc, to produce the finished function.
The answer, for me, is about 10 minutes; for comparison, just "writing a function" (with signature and purpose)
and repl checking examples, takes about half that.
Using accumulator-style recursion, write a function one-long-string that consumes a ListOfString and produces the concatenation of strings in the list in the order they appear in the list. That is, (one-long-string (list "Alice" "Bob" "Eve") returns "AliceBobEve"
Get started
Using the design recipe for writing functions, one starts with a function signature and purpose; these can be copied from the question above and pasted into a Racket function definition stub in the DrRacket definitions area:
(define (one-long-string los) ;; ListOfString -> String ; *stub* ;; *signature*
;; produce the concatenation of los strings in order ; *purpose statement*
"") ; *stub body* (valid result)
The next step is to add a minimal example in the form of a check-expect:
(check-expect (one-long-string empty) "") ; *minimal example*
And then (with DrRacket's Language set to Beginning Student), Run:
The test passed!
>
Follow the recipe
Continue following the design recipe by selecting a template based on the argument type ListOfString -
copy it into the definitions area:
(define (fn lox) ;; ListOfX -> Y ; *template*
;; produce a Y from lox using natural recursion ;
(cond ;
[(empty? lox) ... ] ; ... = "base case value" ;; Y
[else (.... ; .... = "inventory fn(s)" ;; X Y -> Y
(first lox) (fn (rest lox))) ])) ;
(There is a template for "accumulator-style recursion", but this answer will start with the simplest
ListOf template. The solution will be modified to accumulator-style later.)
Edit the template, replacing the generic names with the appropriate ones for this problem, to get:
(define (one-long-string los) ;; ListOfString -> String
;; produce the concatenation of los strings in order
(cond
[(empty? los) "" ] ;; String
[else (.... ;; String String -> String
(first los) (one-long-string (rest los))) ]))
The placeholder ... has been replaced by "" by reference to the first example above.
Note that the signature of .... has been deduced from the signatures of its arguments and result.
Comment out the stub (prefix it with #;), and Run again to confirm that The test passed!.
(Always run after any change to confirm that everything still works, and fix any typos immediately.)
Add another example:
(check-expect (one-long-string (list "Alice")) "Alice")
and Run: the error message confirms that the placeholder .... needs to be replaced.
(This test could be made to pass by adding (define (arg1 x y) x) and using arg1 for ....,
but one can see that something better is likely to be needed.)
The replacement for .... will have signature String String -> String; we don't have such a
function, but checking Strings in Beginning Student
for suitable functions yields the following possibilities:
; format ;; String Any -> String ; *inventory* (all functions with
; string-append ;; String String -> String ; signature String String -> String)
Consider another example:
(check-expect (one-long-string (list "Alice" "Bob")) "AliceBob")
given "Alice" and "Bob", one can produce "AliceBob" with string-append, ie the example can be written:
(check-expect (one-long-string (list "Alice" "Bob")) (string-append "Alice" "Bob"))
This suggests that .... should be string-append; one can now add a final example:
(check-expect (one-long-string (list "Alice" "Bob" "Eve")) "AliceBobEve")
Run again, and the (non-accumulator) function is complete:
#;
(define (one-long-string los) ;; ListOfString -> String ; *stub* ;; *signature*
;; produce the concatenation of los strings in order ; *purpose statement*
"") ; *stub body* (valid result)
(check-expect (one-long-string empty) "") ; *minimal example*
(define (one-long-string los) ;; ListOfString -> String
;; produce the concatenation of los strings in order
(cond
[(empty? los) "" ]
[else (string-append
(first los) (one-long-string (rest los))) ]))
(check-expect (one-long-string (list "Alice")) "Alice")
(check-expect (one-long-string (list "Alice" "Bob")) (string-append "Alice" "Bob"))
(check-expect (one-long-string (list "Alice" "Bob" "Eve")) "AliceBobEve")
All 4 tests passed!
>
Accumulator style
As mentioned earlier, there is a template for "accumulator-style recursion", which uses
features of Advanced Student
language. Why would one use a version of the function incorporating an accumulator?
A common reason is to put the recursive call in tail position.
To explore this style, first try to edit the template to be tail-recursive:
(define (fn lox) ;; ListOfX -> Y ; *template*
;; produce a Y from lox (tail recursive) ;
(cond ;
[(empty? lox) ... ] ; result ;; Y
[else (fn (rest lox)) ; tail recursion
.... (first lox) ; (where do these go?)
])) ;
This can't be right (the placeholder .... and (first lox) don't fit) but continue by
replacing the generic names:
(define (one-long-string los) ;; ListOfString -> String
;; produce the concatenation of los strings in order
(cond
[(empty? los) ... ] ;; String
[else (one-long-string (rest los))
.... (first los) ; ?
]))
The recursive one-long-string call in the partially filled-in template is now in tail position,
with argument (rest los) so that it can deal with all the elements of los,
but to make progress in producing the result the function must do something with (first los).
Where can this be fitted in?
One way to resolve this question is to introduce an argument: with the additional argument,
one-long-string (now renamed to one-long-string-with-arg) has a place in the recursive
call to hold (first los):
(define (one-long-string-with-arg los arg) ;; ListOfString X -> String
;; produce the concatenation of los strings in order, using extra arg
(cond
[(empty? los) (... arg) ] ;; String
[else (one-long-string-with-arg (rest los) (.... arg (first los)))
]))
(define (one-long-string los) ;; ListOfString -> String
;; produce the concatenation of los strings in order
(one-long-string-with-arg los .....))
one-long-string now just calls one-long-string-with-arg, supplying ..... for arg.
Recalling the first two examples:
(check-expect (one-long-string empty) "")
(check-expect (one-long-string (list "Alice")) "Alice")
one can see that a simple replacement for ..... is "", and for (... arg)
just arg. As before, the other examples suggest string-append for .....
The rôle of arg in one-long-string-with-arg is to accumulate a "result so far" value,
so it is renamed rsf, and the complete accumulator style solution is:
#;
(define (one-long-string los) ;; ListOfString -> String ; *stub* ;; *signature*
;; produce the concatenation of los strings in order ; *purpose statement*
"") ; *stub body* (valid result)
(check-expect (one-long-string empty) "") ; *minimal example*
(define (one-long-string-acc los rsf) ;; ListOfString String -> String
;; produce the concatenation of los strings in order using rsf accumulator
(cond
[(empty? los) rsf ]
[else (one-long-string-acc (rest los)
(string-append rsf (first los))) ]))
(define (one-long-string los) ;; ListOfString -> String
;; produce the concatenation of los strings in order, using accumulator
(one-long-string-acc los ""))
(check-expect (one-long-string (list "Alice")) "Alice")
(check-expect (one-long-string (list "Alice" "Bob")) (string-append "Alice" "Bob"))
(check-expect (one-long-string (list "Alice" "Bob" "Eve")) "AliceBobEve")
All 4 tests passed!
>
(to be continued)

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))))

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

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)]))

Converting list of strings to list of ints in Common Lisp

I have a line like "fun,arg1,arg2" <- it is a string
I split this string into list of strings by "," separator. Then I compare "fun" with some string (e.g. "Fibonacci").
Function for splitting (works fine)
(defun split-str (string &optional (r nil))
(let ((n (position "," string
:from-end t
:test #'(lambda (x y)
(find y x :test #'string=)))))
(if n
(split-str (subseq string 0 n)
(cons (subseq string (1+ n)) r))
(cons string r))))
Test function
(defun tmp (a)
(if (string= (nth 0 a) "Fibonacci")
(progn
(setf tab '())
(dolist (n (cdr a))
(cons tab '(parse-integer n))) ; parsing works fine (checked with write)
(write tab)) ; always NIL
;(apply #'parse-integer (apply #'values a)) - doesn't work
(write "nok")))
Calling:
(tmp (split-str "Fibonacci,15,33"))
Why my tab hasn't 2 elements?
cons doesn't change anything; it returns a new list using tab.

return a line of text if match found

I am having some trouble working out how to return a line of text if a match is found.
(set 'wireshark "http://anonsvn.wireshark.org/wireshark/trunk/manuf")
(set 'arptable (map (fn (x) (parse x " ")) (exec "arp -a")))
(define (cleanIPaddress x)
(slice x 1 -1))
(define (cleanMACaddress x)
(upper-case (join (slice (parse x ":") 0 3) ":")))
(define (addIPandMACaddress x)
(list (cleanIPaddress (nth 1 x)) (cleanMACaddress (nth 3 x))))
(set 'arplist (map addIPandMACaddress arptable))
(set 'routerMAC (last (assoc (exec "ipconfig getoption en1 router") arplist)))
(find-all routerMAC (get-url wireshark))
returns
("20:AA:4B")
so I know that the code "works"
but I would like to retrieve the full line of text
"20:AA:4B Cisco-Li # Cisco-Linksys, LLC"
This can be performed simply by using a string-split procedure that allows us to use remove-if (the Common Lisp version of filter) to search through a string split by newlines removing any lines that do not contain the string we are searching for. That would result in a list of every line containing the string. The functions we will define here are already available via various Common Lisp libraries, but for the education purposes, we will define them all ourselves. The code you need works like so:
; First we need a function to split a string by character
(defun string-split (split-string string)
(loop with l = (length split-string)
for n = 0 then (+ pos l)
for pos = (search split-string string :start2 n)
if pos collect (subseq string n pos)
else collect (subseq string n)
while pos))
; Now we will make a function based on string-split to split by newlines
(defun newline-split (string)
(string-split "
" string))
; Finally, we go through our text searching for lines that match our string.
; Make sure to replace 'needle' with the string you wish to search for.
(remove-if #'(lambda (x)
(equal 'nil (search (string-upcase "needle")
(string-upcase x))))
(newline-split haystack))
You should be able to apply this strategy to the code you posted with a few small modifications. This code was tested on SBCL 1.0.55.0-abb03f9, an implementation of ANSI Common Lisp, on Mac OS X 10.7.5.
In the end I used:
(find-all (string routerMAC ".*") (get-url wireshark))