I have a series of expressions to convert from postfix to prefix and I thought that I would try to write a program to do it for me in DrRacket. I am getting stuck with some of the more complex ones such as (10 (1 2 3 +) ^).
I have the very simple case down for (1 2 \*) → (\* 1 2). I have set these expressions up as a list and I know that you have to use cdr/car and recursion to do it but that is where I get stuck.
My inputs will be something along the lines of '(1 2 +).
I have for simple things such as '(1 2 +):
(define ans '())
(define (post-pre lst)
(set! ans (list (last lst) (first lst) (second lst))))
For the more complex stuff I have this (which fails to work correctly):
(define ans '())
(define (post-pre-comp lst)
(cond [(pair? (car lst)) (post-pre-comp (car lst))]
[(pair? (cdr lst)) (post-pre-comp (cdr lst))]
[else (set! ans (list (last lst) (first lst) (second lst)))]))
Obviously I am getting tripped up because (cdr lst) will return a pair most of the time. I'm guessing my structure of the else statement is wrong and I need it to be cons instead of list, but I'm not sure how to get that to work properly in this case.
Were you thinking of something like this?
(define (pp sxp)
(cond
((null? sxp) sxp)
((list? sxp) (let-values (((args op) (split-at-right sxp 1)))
(cons (car op) (map pp args))))
(else sxp)))
then
> (pp '(1 2 *))
'(* 1 2)
> (pp '(10 (1 2 3 +) ^))
'(^ 10 (+ 1 2 3))
Try something like this:
(define (postfix->prefix expr)
(cond
[(and (list? expr) (not (null? expr)))
(define op (last expr))
(define args (drop-right expr 1))
(cons op (map postfix->prefix args))]
[else expr]))
This operates on the structure recursively by using map to call itself on the arguments to each call.
Related
I am trying to come up with a procedure that filters out any value other than a number. For example:
'(1 2 (a) 3) => '(1 2 () 3) or '(1 2 (a 10 11 (b 2 (c))) 3) => '(1 2 (10 11 (2 ())) 3)
This is what I have so far but it doesn't really work because it replaces the non numbers with an empty list instead of nothing:
(define (filter-numbers lst)
(if (null? lst)
'()
(if (list? lst)
(cons
(filter-numbers (car lst))
(filter-numbers (cdr lst)))
(if (number? lst)
lst
'())))
)
The procedure outputs the following:
> (filter-numbers '(1 2 (a) 3))
'(1 2 (()) 3)
instead of: '(1 2 () 3)
You need to check if an element in a sublist is a number before deciding to cons it to the output or not. I think it's easier if we restructure the code a bit; also some tips: don't use list?, prefer pair? as it's faster (unlike list? it doesn't have to traverse the whole list). And prefer cond instead of nesting ifs, your code will be easier to read. This is what I mean:
(define (filter-numbers lst)
(cond ((null? lst) lst)
((not (pair? (car lst)))
; check the element while still in a list, if we wait
; until we reach an atom it's too late to filter it out
(if (number? (car lst))
; either add the element to the output or skip it
(cons (car lst) (filter-numbers (cdr lst)))
(filter-numbers (cdr lst))))
(else (cons
(filter-numbers (car lst))
(filter-numbers (cdr lst))))))
It works as expected:
(filter-numbers '(1 2 (a) 3))
=> (1 2 () 3)
(filter-numbers '(1 2 (a 10 11 (b 2 (c))) 3))
=> '(1 2 (10 11 (2 ())) 3)
I am a beginner in Dr Racket and now I am looking for a solution to reduce nested lists.
For example:
+ 0 (list 1 2 (list 3 (list 4 5) 6) 7 (list (list 8)) empty 9))
should produce 45.
My current function only works for normal lists, but as soon as there is a list in the list, it doesn´t work anymore.
(define (reduce fun neutral lst)
(cond
((empty? lst) neutral)
(else
(fun (car lst)
(reduce fun neutral (rest lst))))))
You must consider the case where (car lst) is also a list. In that case, you will need to reduce (car lst) too, before applying fun.
(define (reduce fun neutral lst)
(cond
[(empty? lst)
neutral]
[(list? (car lst))
(fun (reduce fun neutral (car lst))
(reduce fun neutral (rest lst)))]
[else
(fun (car lst)
(reduce fun neutral (rest lst)))]))
I am learning Racket for understanding principles of programming languages. What I am doing is to add only second elements in pairs of a list. In my understanding, I think I am doing correctly. However, the error message shows up. Please provide me any advise to understand what I am doing wrong.
(define pairs
'((1 5)(6 4)(7 8)(15 10)))
(define (secondSum lst)
(if (null? lst) 0
(+ (cdr (car lst)) (secondSum (cdr lst)))
)
)
>(secondSum pairs)
+: contract violation
expected: number?
given: '()
argument position: 2nd
other arguments...:
10
What I am looking for is
(5 + 4 + 8 + 10)
(cdr (car lst)) should be (car (cdr (car lst))) also (cadr (car lst)) or in racket preferred (second (first lst)) that is if lst is '((1 5)) the result should be 5.
I had to be sure this was right so I ran the program with the fix and verified the result:
(define pairs '((1 5)(6 4)(7 8)(15 10)))
(define (secondSum lst)
(if (null? lst) 0
(+ (car (cdr (car lst))) (secondSum (cdr lst)))
)
)
(secondSum pairs)
(+ 5 4 8 10)
The last two expressions both have the value 27.
Here is my code? Can anyone tell me how to iterate through a list? if the character in the list is alphabetic, I want to add to a new string
#lang racket
(define (conversion input)
(define s (string))
(let ((char (string->list input)))
(cond
[(char-alphabetic? (first (char)))
(string-append s first)]
[(char-alphabetic? (rest (char)))
(string-append s rest)]))
(display s))
Basic iteration is:
(define (copy-list lst)
(if (null? lst)
'()
(cons (car lst)
(copy-list (cdr lst))))
(copy-list '(1 2 3)) ; ==> (1 2 3)
This one actually makes a shallow copy of your list. Sometimes you iterate with keeping some variables to accumulate stuff:
(define (sum-list lst acc)
(if (null lst)
acc
(sum-list (cdr lst) (+ acc (car lst)))))
(sum-list '(1 2 3)) ; ==> 6
Looking at these you'll see a pattern emerges so we have made stuff like map, foldl, and foldr to abstract the iteration:
(define (copy-list-foldr lst)
(foldr cons '() lst)
(define (copy-list-map lst)
(map values lst))
(define (sum-list-foldl lst)
(foldl + 0 lst))
Looking at your challenge I bet you can fix it with a foldr.
I want to make a list of pairs starting from a list, the cdr will be always the same. For example, (make-pair '(1 2 3 4 5)) should return '((1.a)(2.a)(3.a)(4.a)(5.a)).
This is the code i am developing, but it doesn't work and I don't know how to debug it.
(define (make-pair lst)
(if (null? (car lst))
'()
(cons ((car lst) ".a")
(make-pair (cdr lst)))))
Thank you in advance!
You have a couple of errors:
(define (make-pair lst)
(if (null? (car lst)) ; - the base case is when the list is null
'()
(cons ((car lst) ".a") ; - there's a missing cons
; - `a` appears to be a symbol, not a string
; - that's not how we create a dotted pair
; - the surrounding `()` are misplaced
(make-pair (cdr lst)))))
This is the right way:
(define (make-pair lst)
(if (null? lst)
'()
(cons (cons (car lst) 'a)
(make-pair (cdr lst)))))
Or even better, use built-in procedures:
(define (make-pair lst)
(map (lambda (n) (cons n 'a))
lst))
Either way, it works as expected:
(make-pair '(1 2 3 4 5))
=> '((1 . a) (2 . a) (3 . a) (4 . a) (5 . a))