Apologies if this is a common question. Searching up "Racket passing in lambda as an argument" doesn't return much. I'm trying to write a Racket function lsf that takes in an optional lambda function, and applies it to corresponding elements in two same-sized lists. This lambda defaults to addition.
For example, > (lsf '(2 4 5) '(6 7 8) (lambda (a b) (- b a))) should return a list '(4 3 3)
> (lsf '(2 5) '(3 6)) returns '(5 11) (defaults to addition).
Here's what I have so far:
( define ( lsf list1 list2 )
( if ( null? list1 )
'()
( cons( + ( car list1 list2 ))
( lsf ( cdr list1 ) ( cdr list2 )))
)
)
How do I add this default addition function as a parameter (I think it goes after list2?), and how would I use it in place of the "+" that I have after cons?
In addition to rest-args and optionals (see other answers), Racket still has case-lambda (as in r6rs Scheme), so:
#lang racket
(define lsf
(case-lambda
[(list1 list2) ;; (Listof Number) (Listof Number) -> (Listof Number)
;; produce list of sums of corresponding elements of list1, list2
(lsf list1 list2 +) ]
[(list1 list2 combine) ;; (Listof X) (Listof Y) (X Y -> Z) -> (Listof Z)
;; produce list applying combine to corresponding elements
(if (null? list1)
'()
(cons (combine (car list1) (car list2))
(lsf (cdr list1) (cdr list2) combine))) ]))
And then:
> (lsf '(2 5) '(3 6))
'(5 11)
> (lsf '(1 2 3) '(#\a #\b #\c) make-string)
'("a" "bb" "ccc")
Use . in the parameter list to define a rest-arg, which gets a list of all the additional arguments. If the optional argument is supplied, this will be non-null and you can get the argument as its first element.
(define (lsf list1 list2 . rest)
(if (null? list1)
'()
(let ((func (if (null? rest) + (first rest)))) ; default func to +
(cons (func (car list1) (car list2))
(lsf (cdr list1) (cdr list2) func)))))
If it is #lang racket that is used you can use by position optional parameters:
(define (lsf list1 list2 [combine +])
(if (null? list1)
'()
(cons (combine (car list1) (car list2))
(lsf (cdr list1) (cdr list2) combine))))
Related
I am trying to write a Racket function with tail recursion, it should return the inverted list but the last element should remain in the last position.
That is, I need to get from the example:
(reversar-lista '(1 2 3 4))
>(3 2 1 4)
Here is what I have so far:
(define (reversar-lista lista)
(define (reversa-aux lista aux)
(if (null? lista) aux
(reversa-aux (cdr lista) (reverse (cons (car lista) aux)))
)
)
(reversa-aux lista '())
)
I get the following output:
(3 1 2 4)
It's possible to solve this question using only built-in procedures, there's no need to implement explicit looping logic:
(define (reversar-lista lista)
(if (null? lista)
'()
(append (reverse (drop-right lista 1))
(take-right lista 1))))
Of course, it's also possible to write a solution by hand - but you have to be careful with the edge cases, in particular watch out for the empty list case.
The main problems with your solution are that you must stop the recursion before the last element, and that you must not reverse the result at every iteration, the list is being built in reverse anyway. This is what I mean:
(define (reversar-lista lista)
(define (reversa-aux lista aux)
(if (null? (cdr lista))
(append aux (list (car lista)))
(reversa-aux (cdr lista) (cons (car lista) aux))))
(if (null? lista)
'()
(reversa-aux lista '())))
Either way, it works as expected:
(reversar-lista '())
=> '()
(reversar-lista '(1))
=> '(1)
(reversar-lista '(1 2))
=> '(1 2)
(reversar-lista '(1 2 3))
=> '(2 1 3)
(reversar-lista '(1 2 3 4))
=> '(3 2 1 4)
So I want to run a definition, from my vecfn that calls on vecadd, but when it calls it goes with #procedure:vecadd. Also planning to do it with other procedure such as - and /.
I've tried to look up what the #procedure is but it only gave me arithmetic examples. It doesn't address the issue of why #procedure is popping up.
(define (vecfn x list1 list2)
(if (eqv? x +)
vecadd
(if (eqv? x -)
vecsub
(if (eqv? x /)
vecdiv
'()))))
(define (vecadd list1 list2)
(cond ((and (pair? list1) (pair? list2))
(cons (+ (car list1) (car list2))
(vecadd (cdr list1) (cdr list2))))
((pair? list1) list1)
(else list2)))
Using (vecfn + '(1 2 3) '(1 2 3)) would get me (2 4 6) but instead gave me #procedure:vecadd
You're not actually calling the vecadd, vecsub and vecdiv procedures, vecfn is returning the procedures themselves. Try this:
(define (vecfn x list1 list2)
(if (eqv? x +)
; invoke procedure with two parameters
(vecadd list1 list2)
(if (eqv? x -)
(vecsub list1 list2)
(if (eqv? x /)
(vecdiv list1 list2)
'()))))
In Scheme you call a procedure by surrounding it with () and passing the parameters separated by spaces: (vecadd list1 list2).
I've created a function that should return the elements that the two lists do not have in common. Currently, they are outputting exactly what is passed into it. Any suggestions on how to fix this?
(define (findDifference lst1 lst2)
(if (null? lst1) lst2
(cons (car lst1) (findDifference (cdr lst1) lst2))))
(findDifference '(2 3 4 (2 3) 2 (4 5)) '(2 4 (4 5))
Current Output: (2 3 4 (2 3) 2 (4 5) 2 4 (4 5))
Desired Output: (3 (2 3))
You're asking for the symmetric difference of two lists. Try this:
(define (diff list1 list2)
(union (complement list1 list2)
(complement list2 list1)))
Using the following helper procedures:
(define (union list1 list2)
(cond ((null? list1) list2)
((member (car list1) list2) (union (cdr list1) list2))
(else (cons (car list1) (union (cdr list1) list2)))))
(define (complement list1 list2)
(cond ((null? list1) '())
((member (car list1) list2) (complement (cdr list1) list2))
(else (cons (car list1) (complement (cdr list1) list2)))))
Also notice that if you're using Racket you can simply use the built-in set-symmetric-difference procedure for the same effect. For example:
(diff '(2 3 4 (2 3) 2 (4 5)) '(2 4 (4 5)))
=> '(3 (2 3))
Since it seems like homework and I do not want to spoil the fun, here is the brute force algorithm, with some bits left out. If you are really stuck I will give you the full source.
(define (sym-diff xs ys)
;; Since we have the helper function we can determine all the elements that are in the first list,
;; but not in the second list.
;; Then we can pass this intermediate result to the second call to sym-diff-helper.
;;This will return us all the elements that are in the second list but not the first.
(let ((in-first-not-second ...))
(sym-diff-helper ys xs in-first-not-second)))
;; This function will return all the elements from the first list that are not in the second list!
(define (sym-diff-helper xs ys acc)
(cond
;; If the first list is empty we have checked it.
(...
acc)
;; If the first list is not empty yet, check if the first element
;; is in the second list.
;; If so, discard it and continue with the rest of the list.
((member ... ...)
(sym-diff-helper ... ... ...)
;; If the first element of the first list is not in the second list,
;; add it to the accumulator and continue with the rest of the list.
(else
(sym-diff-helper ... ... ...)))
(sym-diff-helper '(1 2 3) '(2 3 4) '())
;; == (1)
(sym-diff-helper '(1 2 (3 4) 5) '(2 3 4) '())
;; == (5 (3 4) 1)
(sym-diff '(2 3 4 (2 3) 2 (4 5)) '(2 4 (4 5)))
;; == ((2 3) 3)
Note that I have chosen to use member. There are a few other search functions but they were not well suited in this case. Hence, I left it there. More info on the search functions can be found here: http://docs.racket-lang.org/reference/pairs.html#%28part..List.Searching%29
I'm trying to use direct recursion to sort a list into a list of sublists of even and odd positions.
So (split '(1 2 3 4 5 6)) returns ((1 3 5) (2 4 6))
and (split '(a 2 b 3)) returns ((a b) (2 3))
So far, I have the following code:
(define split
(lambda (ls)
(if (or (null? ls) (null? (cdr ls)))
(values ls '())
(call-with-values
(lambda () (split (cddr ls)))
(lambda (odds evens)
(values (cons (car ls) odds)
(cons (cadr ls) evens)))))))
However, now I'm stumped on how to store multiple outputs into a single list.
I know that calling it like this:
(call-with-values (lambda () (split '(a b c d e f))) list)
returns a list of sublists, however I would like the function itself to return a list of sublists. Is there a better way to do this that doesn't involve the use of values and call-with-values?
Sure. Here's an adapted version of your code:
(define (split ls)
(if (or (null? ls) (null? (cdr ls)))
(list ls '())
(let ((next (split (cddr ls))))
(list (cons (car ls) (car next))
(cons (cadr ls) (cadr next))))))
One thing that I like about the code in the question is that it uses odds and evens in a way that reflects the specification.
The objectives of this solution are:
Readability.
To reflect the language of the specification in the code.
To use O(n) space during execution.
It uses an internal function with accumulators and a trampoline.
#lang racket
;; List(Any) -> List(List(Any) List(Any))
(define (split list-of-x)
(define end-of-list (length list-of-x))
;; List(Any) List(Any) List(Any) Integer -> List(List(Any) List(Any))
(define (looper working-list odds evens index)
(cond [(> index end-of-list)
(list (reverse odds)
(reverse evens))]
[(odd? index)
(looper (rest working-list)
(cons (car working-list) odds)
evens
(add1 index))]
[(even? index)
(looper (rest working-list)
odds
(cons (car working-list) evens)
(add1 index))]
[else
(error "split: unhandled index condition")]))
(looper list-of-x null null 1))
Here's an answer that should be clear if you are familiar with match syntax. It is identical in form and function to Chris Jester-Young's answer, but uses match to clarify list manipulation.
#lang racket
(define (split ls)
(match ls
[`(,first ,second ,rest ...)
(match (split rest)
[`(,evens ,odds) (list (cons first evens)
(cons second odds))])]
[_ (list ls '())]))
(: split ((list-of natural) -> (list-of (list-of natural))))
(define split
(lambda (xs)
(list (filter even? xs) (filter odd? xs))))
(: filter ((%a -> boolean) (list-of %a) -> (list-of %a)))
(define filter
(lambda (p xs)
(fold empty (lambda (first result)
(if (p first)
(make-pair first result)
result)) xs)))
(check-expect (split (list 1 2 3 4 5 6)) (list (list 2 4 6) (list 1 3 5)))
i think this one is also really easy to understand..
I'm trying to reverse a list, here's my code:
(define (reverse list)
(if (null? list)
list
(list (reverse (cdr list)) (car list))))
so if i enter (reverse '(1 2 3 4)), I want it to come out as (4 3 2 1), but right now it's not giving me that. What am I doing wrong and how can I fix it?
The natural way to recur over a list is not the best way to solve this problem. Using append, as suggested in the accepted answer pointed by #lancery, is not a good idea either - and anyway if you're learning your way in Scheme it's best if you try to implement the solution yourself, I'll show you what to do, but first a tip - don't use list as a parameter name, that's a built-in procedure and you'd be overwriting it. Use other name, say, lst.
It's simpler to reverse a list by means of a helper procedure that accumulates the result of consing each element at the head of the result, this will have the effect of reversing the list - incidentally, the helper procedure is tail-recursive. Here's the general idea, fill-in the blanks:
(define (reverse lst)
(<???> lst '())) ; call the helper procedure
(define (reverse-aux lst acc)
(if <???> ; if the list is empty
<???> ; return the accumulator
(reverse-aux <???> ; advance the recursion over the list
(cons <???> <???>)))) ; cons current element with accumulator
Of course, in real-life you wouldn't implement reverse from scratch, there's a built-in procedure for that.
Here is a recursive procedure that describes an iterative process (tail recursive) of reversing a list in Scheme
(define (reverse lst)
(define (go lst tail)
(if (null? lst) tail
(go (cdr lst) (cons (car lst) tail))))
(go lst ())))
Using substitution model for (reverse (list 1 2 3 4))
;; (reverse (list 1 2 3 4))
;; (go (list 1 2 3 4) ())
;; (go (list 2 3 4) (list 1))
;; (go (list 3 4) (list 2 1))
;; (go (list 4) (list 3 2 1))
;; (go () (list 4 3 2 1))
;; (list 4 3 2 1)
Here is a recursive procedure that describes a recursive process (not tail recursive) of reversing a list in Scheme
(define (reverse2 lst)
(if (null? lst) ()
(append (reverse2 (cdr lst)) (list (car lst)))))
(define (append l1 l2)
(if (null? l1) l2
(cons (car l1) (append (cdr l1) l2))))
Using substitution model for (reverse2 (list 1 2 3 4))
;; (reverse2 (list 1 2 3 4))
;; (append (reverse2 (list 2 3 4)) (list 1))
;; (append (append (reverse2 (list 3 4)) (list 2)) (list 1))
;; (append (append (append (reverse2 (list 4)) (list 3)) (list 2)) (list 1))
;; (append (append (append (append (reverse2 ()) (list 4)) (list 3)) (list 2)) (list 1))
;; (append (append (append (append () (list 4)) (list 3)) (list 2)) (list 1))
;; (append (append (append (list 4) (list 3)) (list 2)) (list 1))
;; (append (append (list 4 3) (list 2)) (list 1))
;; (append (list 4 3 2) (list 1))
;; (list 4 3 2 1)
Tail recursive approach using a named let:
(define (reverse lst)
(let loop ([lst lst] [lst-reversed '()])
(if (empty? lst)
lst-reversed
(loop (rest lst) (cons (first lst) lst-reversed)))))
This is basically the same approach as having a helper function with an accumulator argument as in Oscar's answer, where the loop binding after let makes the let into an inner function you can call.
Here's a solution using build-list procedure:
(define reverse
(lambda (l)
(let ((len (length l)))
(build-list len
(lambda (i)
(list-ref l (- len i 1)))))))
This one works but it is not a tail recursive procedure:
(define (rev lst)
(if (null? lst)
'()
(append (rev (cdr lst)) (car lst))))
Tail recursive solution:
(define (reverse oldlist)
(define (t-reverse oldlist newlist)
(if (null? oldlist)
newlist
(t-reverse (cdr oldlist) (cons (car oldlist) newest))))
(t-reverse oldlist '()))
Just left fold the list using cons:
(define (reverse list) (foldl cons null list))
This is also efficient because foldl is tail recursive and there is no need for append. This can also be done point-free (using curry from racket):
(define reverse (curry foldl cons null))
(define reverse?
(lambda (l)
(define reverse-aux?
(lambda (l col)
(cond
((null? l) (col ))
(else
(reverse-aux? (cdr l)
(lambda ()
(cons (car l) (col))))))))
(reverse-aux? l (lambda () (quote ())))))
(reverse? '(1 2 3 4) )
One more answer similar to Oscar's. I have just started learning scheme, so excuse me in case you find issues :).
There's actually no need for appending or filling the body with a bunch of lambdas.
(define (reverse items)
(if (null? items)
'()
(cons (reverse (cdr items)) (car items))))
I think it would be better to use append instead of cons
(define (myrev l)
(if (null? l)
'()
(append (myrev (cdr l)) (list (car l)))
)
)
this another version with tail recursion
(define (myrev2 l)
(define (loop l acc)
(if (null? l)
acc
(loop (cdr l) (append (list (car l)) acc ))
)
)
(loop l '())
)