I need to do something basically like this:
(define test
(λ (ls1 ls2)
(cond
((empty? ls2) null)
(else
(append ls1 (car ls2)) (test ls1 (cdr ls2))) (displayln ls1))))
The issue is the else-clause and the function that follows it. I need both clauses of the else-clause to execute and then I need the last function to execute but I can't get the syntax right.
I need (test '(1 2 3) '(4 5 6)) to result in displaying '(1 2 3 4 5 6) and it has to use the recursive call.
Any advice is appreciated.
Thanks.
There is several problem there. First you make an append on a list and an atom (not a list)... at least if (car l2) is not a list. Second you probably think that (append l1 (list (car l2)) modifies l1. But this is not the case. The result is a new list.
To sequence your operation you can do as larsmans have said. But you can also write the following
(define (test l1 l2)
(if (null? l2)
(displayln l1)
(let ((l1-follow-by-car-l2 (append l1 (list (car l2)))))
(test l1-follow-by-car-l2 (cdr l2)) ))
This has exactly the same behavior.
If you desperately want to solve this recursively, and you don't care about the return value, use
(define (test l1 l2)
(if (null? l2)
(displayln l1)
(test (append l1 (list (car l2))) (cdr l2))))
(This is very inefficient btw: O(n × m) memory allocations.)
Related
We've recently started learning Common Lisp in our class. I am trying to implement a function that takes two list and outputs their common elements. We are restricted to using basic functional forms.
(defun myCommon(L1 L2)
(cond
((null L1) nil) ;;check if the first list is empty
((null L2) nil) ;;check if the second list is empty
((eq (car L1) (car L2)) ((car L1) (myCommon (cdr L1) L2)))
(t (myCommon (cdr L1) L2)) ;;if they are not the same, recurse myCommon with L1 as (cdr L1)
)
)
My problem is that I cannot understand why it results as a type error (offending datum: (CAR L1)). It seems to be expecting a function type as far as I could make sense of it.
Error: TYPE-ERROR :DATUM (CAR L1) :EXPECTED-TYPE FUNCTION
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by COND.
TYPE-ERROR :DATUM (CAR L1) :EXPECTED-TYPE FUNCTION
Broken at COND.
Your problem is due to the fact that in the second branch of the cond, the expression which is evaluated when the condition about the equality of the two cars is true is: ((car L1) (myCommon (cdr L1) L2))).
Here you have a list with two elements ((car L1) (myCommon...)) in a position where a form is required (that is list with a structure like (function argument1 argument2 ...)). So the system gives an error since (car l1) is not a function. What I suppose you want to do is to produce a new list with those two arguments, which could be obtained for instance by “consing” them, like in (cons (car L1) (myCommon...)), so this is your function rewritten:
(defun myCommon(L1 L2)
(cond ((null L1) nil) ;;check if the first list is empty
((null L2) nil) ;;check if the second list is empty
((eq (car L1) (car L2)) (cons (car L1) (myCommon (cdr L1) L2)))
(t (myCommon (cdr L1) L2)))) ;;if they are not the same, recurse myCommon with L1 as (cdr L1)
Note that if you try this function for instance on: (mycommon '(1 2 3) '(1 2 3 4) you will find that the answer is (1) and not (1 2 3). This is because you are “consuming” only the first argument (by recurring on it with (cdr L1)). So, you need to correct the function “consuming” also the second argument when necessary.
I'm new to racket and trying to write a function that checks if a list is in strictly ascending order.
'( 1 2 3) would return true
'(1 1 2) would return false (repeats)
'(3 2 4) would return false
My code so far is:
Image of code
(define (ascending? 'list)
(if (or (empty? list) (= (length 'list) 1)) true
(if (> first (first (rest list))) false
(ascending? (rest list)))))
I'm trying to call ascending? recursively where my base case is that the list is empty or has only 1 element (then trivially ascending).
I keep getting an error message when I use check-expect that says "application: not a procedure."
I guess you want to implement a procedure from scratch, and Alexander's answer is spot-on. But in true functional programming style, you should try to reuse existing procedures to write the solution. This is what I mean:
(define (ascending? lst)
(apply < lst))
It's shorter, simpler and easier to understand. And it works as expected!
(ascending? '(1 2 3))
=> #t
(ascending? '(1 1 2))
=> #f
Some things to consider when writing functions:
Avoid using built in functions as variable names. For example, list is a built in procedure that returns a newly allocated list, so don't use it as an argument to your function, or as a variable. A common convention/alternative is to use lst as a variable name for lists, so you could have (define (ascending? lst) ...).
Don't quote your variable names. For example, you would have (define lst '(1 2 3 ...)) and not (define 'lst '(1 2 3 ...)).
If you have multiple conditions to test (ie. more than 2), it may be cleaner to use cond rather than nesting multiple if statements.
To fix your implementation of ascending? (after replacing 'list), note on line 3 where you have (> first (first (rest list))). Here you are comparing first with (first (rest list)), but what you really want is to compare (first lst) with (first (rest lst)), so it should be (>= (first lst) (first (rest lst))).
Here is a sample implementation:
(define (ascending? lst)
(cond
[(null? lst) #t]
[(null? (cdr lst)) #t]
[(>= (car lst) (cadr lst)) #f]
[else
(ascending? (cdr lst))]))
or if you want to use first/rest and true/false you can do:
(define (ascending? lst)
(cond
[(empty? lst) true]
[(empty? (rest lst)) true]
[(>= (first lst) (first (rest lst))) false]
[else
(ascending? (rest lst))]))
For example,
> (ascending? '(1 2 3))
#t
> (ascending? '(1 1 2))
#f
> (ascending? '(3 2 4))
#f
If you write down the properties of an ascending list in bullet form;
An ascending list is either
the empty list, or
a one-element list, or
a list where
the first element is smaller than the second element, and
the tail of the list is ascending
you can wind up with a pretty straight translation:
(define (ascending? ls)
(or (null? ls)
(null? (rest ls))
(and (< (first ls) (first (rest ls)))
(ascending? (rest ls)))))
This Scheme solution uses an explicitly recursive named let and memoization:
(define (ascending? xs)
(if (null? xs) #t ; Edge case: empty list
(let asc? ((x (car xs)) ; Named `let`
(xs' (cdr xs)) )
(if (null? xs') #t
(let ((x' (car xs'))) ; Memoization of `(car xs)`
(if (< x x')
(asc? x' (cdr xs')) ; Tail recursion
#f)))))) ; Short-circuit termination
(display
(ascending?
(list 1 1 2) )) ; `#f`
I have tried many times but I still stuck in this problem, here is my input:
(define *graph*
'((a . 2) (b . 2) (c . 1) (e . 1) (f . 1)))
and I want the output to be like this: ((2 a b) (1 c e f))
Here is my code:
(define group-by-degree
(lambda (out-degree)
(if (null? (car (cdr out-degree)))
'done
(if (equal? (cdr (car out-degree)) (cdr (car (cdr out-degree))))
(list (cdr (car out-degree)) (append (car (car out-degree))))
(group-by-degree (cdr out-degree))))))
Can you please show me what I have done wrong cos the output of my code is (2 a). Then I think the idea of my code is correct.
Please help!!!
A very nice and elegant way to solve this problem, would be to use hash tables to keep track of the pairs found in the list. In this way we only need a single pass over the input list:
(define (group-by-degree lst)
(hash->list
(foldl (lambda (key ht)
(hash-update
ht
(cdr key)
(lambda (x) (cons (car key) x))
'()))
'#hash()
lst)))
The result will appear in a different order than the one shown in the question, but nevertheless it's correct:
(group-by-degree *graph*)
=> '((1 f e c) (2 b a))
If the order in the output list is a problem try this instead, it's less efficient than the previous answer, but the output will be identical to the one in the question:
(define (group-by-degree lst)
(reverse
(hash->list
(foldr (lambda (key ht)
(hash-update
ht
(cdr key)
(lambda (x) (cons (car key) x))
'()))
'#hash()
lst))))
(group-by-degree *graph*)
=> '((2 a b) (1 c e f))
I don't know why the lambda is necessary; you can directly define a function with (define (function arg1 arg2 ...) ...)
That aside, however, to put it briefly, the problen is that the cars and cdrs are messed up. I couldn't find a way to tweak your solution to work, but here is a working implementation:
; appends first element of pair into a sublist whose first element
; matches the second of the pair
(define (my-append new lst) ; new is a pair
(if (null? lst)
(list (list (cdr new) (car new)))
(if (equal? (car (car lst)) (cdr new))
(list (append (car lst) (list (car new))))
(append (list (car lst)) (my-append new (cdr lst)))
)
)
)
; parses through a list of pairs and appends them into the list
; according to my-append
(define (my-combine ind)
(if (null? ind)
'()
(my-append (car ind) (my-combine (cdr ind))))
)
; just a wrapper for my-combine, which evaluates the list backwards
; this sets the order right
(define (group-by-degree out-degree)
(my-combine (reverse out-degree)))
"define a procedure 'reduce-per-key' which a procedure reducef and a list of associations in which each key is paired with a list. The output is a list of the same structure except that each key is now associated with the result of applying reducef to its associated list"
I've already written 'map-per-key' and 'group-by-key' :
(define (map-per-key mapf lls)
(cond
[(null? lls) '()]
[else (append (mapf (car lls))(map-per-key mapf (cdr lls)))]))
(define (addval kv lls)
(cond
[(null? lls) (list (list (car kv)(cdr kv)))]
[(eq? (caar lls) (car kv))
(cons (list (car kv) (cons (cadr kv) (cadar lls)))(cdr lls))]
[else (cons (car lls)(addval kv (cdr lls)))]))
(define (group-by-key lls)
(cond
[(null? lls) '()]
[else (addval (car lls) (group-by-key (cdr lls)))]))
how would I write the next step, 'reduce-per-key' ? I'm also having trouble determining if it calls for two arguments or three.
so far, I've come up with:
(define (reduce-per-key reducef lls)
(let loop ((val (car lls))
(lls (cdr lls)))
(if (null? lls) val
(loop (reducef val (car lls)) (cdr lls)))))
however, with a test case such as:
(reduce-per-key
(lambda (kv) (list (car kv) (length (cadr kv))))
(group-by-key
(map-per-key (lambda (kv) (list kv kv kv)) xs)))
I receive an incorrect argument count, but when I try to write it with three arguments, I also receive this error. Anyone know what I'm doing wrong?
Your solution is a lot more complicated than it needs to be, and has several errors. In fact, the correct answer is simple enough to make unnecessary the definition of new helper procedures. Try working on this skeleton of a solution, just fill-in the blanks:
(define (reduce-per-key reducef lls)
(if (null? lls) ; If the association list is empty, we're done
<???> ; and we can return the empty list.
(cons (cons <???> ; Otherwise, build a new association with the same key
<???>) ; and the result of mapping `reducef` on the key's value
(reduce-per-key <???> <???>)))) ; pass reducef, advance the recursion
Remember that there's a built-in procedure for mapping a function over a list. Test it like this:
(reduce-per-key (lambda (x) (* x x))
'((x 1 2) (y 3) (z 4 5 6)))
> '((x 1 4) (y 9) (z 16 25 36))
Notice that each association is composed of a key (the car part) and a list as its value (the cdr part). For example:
(define an-association '(x 3 6 9))
(car an-association)
> 'x ; the key
(cdr an-association)
> '(3 6 9) ; the value, it's a list
As a final thought, the name reduce-per-key is a bit misleading, map-per-key would be a lot more appropriate as this procedure can be easily expressed using map ... but that's left as an exercise for the reader.
UPDATE:
Now that you've found a solution, I can suggest a more concise alternative using map:
(define (reduce-per-key reducef lls)
(map (lambda (e) (cons (car e) (map reducef (cdr e))))
lls))
First off, this is homework, but I am simply looking for a hint or pseudocode on how to do this.
I need to sum all the items in the list, using recursion. However, it needs to return the empty set if it encounters something in the list that is not a number. Here is my attempt:
(DEFINE sum-list
(LAMBDA (lst)
(IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst))))
'()
(+
(CAR lst)
(sum-list (CDR lst))
)
)
)
)
This fails because it can't add the empty set to something else. Normally I would just return 0 if its not a number and keep processing the list.
I suggest you use and return an accumulator for storing the sum; if you find a non-number while traversing the list you can return the empty list immediately, otherwise the recursion continues until the list is exhausted.
Something along these lines (fill in the blanks!):
(define sum-list
(lambda (lst acc)
(cond ((null? lst) ???)
((not (number? (car lst))) ???)
(else (sum-list (cdr lst) ???)))))
(sum-list '(1 2 3 4 5) 0)
> 15
(sum-list '(1 2 x 4 5) 0)
> ()
I'd go for this:
(define (mysum lst)
(let loop ((lst lst) (accum 0))
(cond
((empty? lst) accum)
((not (number? (car lst))) '())
(else (loop (cdr lst) (+ accum (car lst)))))))
Your issue is that you need to use cond, not if - there are three possible branches that you need to consider. The first is if you run into a non-number, the second is when you run into the end of the list, and the third is when you need to recurse to the next element of the list. The first issue is that you are combining the non-number case and the empty-list case, which need to return different values. The recursive case is mostly correct, but you will have to check the return value, since the recursive call can return an empty list.
Because I'm not smart enough to figure out how to do this in one function, let's be painfully explicit:
#lang racket
; This checks the entire list for numericness
(define is-numeric-list?
(lambda (lst)
(cond
((null? lst) true)
((not (number? (car lst))) false)
(else (is-numeric-list? (cdr lst))))))
; This naively sums the list, and will fail if there are problems
(define sum-list-naive
(lambda (lst)
(cond
((null? lst) 0)
(else (+ (car lst) (sum-list-naive (cdr lst)))))))
; This is a smarter sum-list that first checks numericness, and then
; calls the naive version. Note that this is inefficient, because the
; entire list is traversed twice: once for the check, and a second time
; for the sum. Oscar's accumulator version is better!
(define sum-list
(lambda (lst)
(cond
((is-numeric-list? lst) (sum-list-naive lst))
(else '()))))
(is-numeric-list? '(1 2 3 4 5))
(is-numeric-list? '(1 2 x 4 5))
(sum-list '(1 2 3 4 5))
(sum-list '(1 2 x 4 5))
Output:
Welcome to DrRacket, version 5.2 [3m].
Language: racket; memory limit: 128 MB.
#t
#f
15
'()
>
I suspect your homework is expecting something more academic though.
Try making a "is-any-nonnumeric" function (using recursion); then you just (or (is-any-numeric list) (sum list)) tomfoolery.