how to build a function like "list? function" - list

How to simulation "list? function" by define-struct.
I want to define struct to binary tree and check each mycons's right node is make-mycons or empty.
Only focus on check right node needed be mycons or empty.
(I already found list?'s sourece code from github but it beyond my ability.)
#lang racket
(define-struct mycons (left right) #:mutable #:transparent)
(define (mylist? l)
(cond
[(empty? l) #t]
[(mycons? l) ...]
[... ]))
(define correct (make-mycons (make-mycons 1 empty) (make-mycons 1 empty)))
(define wrong (make-mycons 3 (make-mycons 2 4)))
;;; expect
(equal? (mylist? empty) #t)
(equal? (mylist? correct) #t)
(equal? (mylist? wrong) #f)

A simple version of list?:
(define (my-list? x)
(cond
[(eq? x '()) #t]
[(pair? x) (my-list? (cdr x))]
[else #f])
The builtin list? is smarter though. When cons is called it checks whether the last argument is a list and if it is, flips a bit in the internal representation of the cons cell. This means that the builtin list? is O(1) rather than O(n) as the solution above.

Related

scheme iteration of summing in lists

i want to ask if someone wants to help me with a iterative scheme code that gives the sum of two lists. I already have the recursive version of the code.
(define (sum-lists l1 l2)(cond ((and (null? l1) (null? l2)) '())
((null? l1) l2)
((null? l2) l1)
(else (cons (+ (car l1) (car l2)) (sum-lists (cdr l1) (cdr l2))))))
The general "iterative procedure" recipe:
Write a helper function that takes an accumulator parameter.
Create each intermediate result in the accumulator.
When you terminate the recursion, return the accumulator.
Pass it a suitable initial accumulator.
It's common when transforming lists to accumulate the result in reverse and then reverse the result when you're done.
A trivial example, incrementing each list element by one:
(define (add-1 ls)
(if (null? ls)
'()
(cons (+ 1 (car ls)) (add-1 (cdr ls)))))
To make it iterative, create a helper function where you cons to the accumulator instead of the recursive result:
(define (add-one ls acc)
(if (null? ls)
(reverse acc)
(add-one (cdr ls) (cons (+ 1 (car ls)) acc))))
(Note that, except for the introduction of acc, the recursion contains the same parts as before but in a different order.)
Then you start it off with an empty accumulator:
(define (add-1 ls)
(add-one ls '()))
Your case has slightly more involved base cases since you need to accomodate inputs of different lengths.
Finishing it left as an exercise.
(Another exercise: figure out why your first condition, (and (null? l1) (null? l2)), is unnecessary.)

Procedures on lists (scheme)

I am writing a procedure which returns a list with all of the negative odd and positive
even integers removed (strings can stay), by using lambda in the primitive filter procedure. I also am avoiding using recursion, but that is what's stumping me.
What I have so far is:
(define (f2b lst)
(cond ((null? lst)'()) ; if the list is empty, return the empty list
((pair? (car lst)) ; if the current element isn't a list
(filter (lambda (x) (or (even? x) (positive? x))) (car lst))
(filter (lambda (x) (or (odd? x) (negative? x))) (car lst)))
(else (string? (car lst)) ;otherwise, if the current element is a string,
(car lst) ; then return that element
(f2b (cdr lst)))))
I'm also not sure how I can apply both of the filter procedures at the same time.
It's way simpler than that. All you have to do is filter the list. You just need the appropriate predicate.
When do you want to keep an element? You phrased it in terms of what you want to remove, so let's start with that. You want to remove if it's a negative odd or a positive even integer, and leave everything else in. It's easier to break it down into smaller functions.
(define (positive-even? x) (and (positive? x) (even? x)))
(define (negative-odd? x) (and (negative? x) (odd? x)))
(define (remove-num? x) (or (positive-even? x) (negative-odd? x)))
This defines whether to keep a number. But the list element might not be a number. So we
keep it if it's not a number, or if it doesn't match remove-num?:
(define (keep-element? x) (or (not (number? x)) (not (remove-num? x))
Then your function just has to call filter:
(define (f2b lst) (filter keep-element? lst))
Seems to work:
(f2b '(-4 -3 -2 -1 0 1 2 3 4 "a string" "another"))
=> (-4 -2 0 1 3 "a string" "another")
Here's how it would look as one big honkin' function:
(define (f2b lst)
(filter
(lambda (x)
(or (not (number? x))
(not (or (and (positive? x) (even? x))
(and (negative? x) (odd? x))))))
lst)
Personally, the nested or not or and gets a bit hard to read for my taste...
Ok, apparently you have nested lists. All you have to do here is map the result of the filter with a function which:
when given a list, returns (f2b lst)
otherwise, returns the element unchanged.
I will leave it as an exercise for you since, if you thought my function could possibly work on a nested list, clearly you have a lot of learning to do...

Scheme, Check if anything in two lists are the same

Is it possible to check two list against each other if anything is the same in them?
(check-list '(hey cookie monkey) '(apple pizza cookie) ==> #t
I tried something like
(define (check-list list element)
(let ((x list))
(cond ((null? x) #f)
((eq? (car x) (car element)) #t)
(else (check-list (cdr x) element))))
(check-list list (cdr element)))
I know this is not correctly written but don't know how to tackle this problem.
Anyone that can help me?
Sometimes it helps to formulate the process of the solution to a problem in your natural language. Let's simplify the problem a bit.
How do you check if one element is contained in a list? One way to do that would be to compare that one element with each element in the list until you found it - somewhere along the lines you have already done - but not quite. A quick draft would be:
(define (member? e lst)
(cond ((null? lst) #f) ; empty list doesn't contain e
(or (eq? e <??>) ; either the first element is e or
(member? e <??>))) ; the rest of the list contains e
We can use that previous knowledge to solve the real problem at hand. We know how to search for one element in a list, and now we need to search for each element in a list in another list.
(define (check-list lst1 lst2)
(if (or (null? lst1) (null? lst2)) #f ; empty list(s) share no elements
(or (member? <??> <??>) ; first element of lst1 in lst2?
(member? <??> <??>)))) ; rest of lst1 in lst2?
The <??> should be substituded with the appropriate expressions for selecting the parts of the lists.
Similar to a prior answer but exploiting logic primitives:
(define (intersect? list1 list2)
(and (not (null? list1))
(or (member (car list1) list2)
(intersect? (cdr list1) list2))))
If the lists are wicket long you might want to hash the first list and then just iterate through the second. This uses R5RS with srfi-69 and for small lists you'll get a little overhead but
(require srfi/69); alist->hash-table, hash-table-ref/default
(define (intersect? list1 list2)
(let ((hash (alist->hash-table (map (lambda (x) (cons x x)) list2) equal? )))
(let loop ((list list1))
(and (not (null? list))
(or (hash-table-ref/default hash (car list) #f)
(loop (cdr list)))))))
There seems to be a little confusion. The "big" problem here is how to determine if two lists share at least one element in common, let's write a procedure for that called element-in-common?. Before tackling this problem, we need to determine if a single element belongs in one list, that's what check-list should do (notice that in your code check-list receives as a second parameter an element, but you're treating it as if it were a list of elements).
You don't have to write the check-list procedure, it already exists and it's called member. With that knowledge in hand, we can solve the big problem - how to determine if at least one of the elements in one list (let's call it lst1) is in another list (called lst2)?
Simple: we iterate over each of the elements in lst1 using recursion, asking for each one if it belongs in lst2. If just one element of lst1 is a member of lst2, we return #t. If none of the elements in lst1 is in lst2, we return #f. Something like this:
(define (element-in-common? lst1 lst2)
(cond (<???> ; is the first list empty?
<???>) ; then there are no elements in common
((member <???> lst2) ; is the current element of `lst1` in `lst2`?
<???>) ; then there IS an element in common
(else ; otherwise
(element-in-common? <???> lst2)))) ; advance recursion
Don't forget to test your code:
(element-in-common? '(hey cookie monkey) '(apple pizza cookie))
=> #t
(element-in-common? '(hey cookie monkey) '(apple pizza pie))
=> #f
You can use memq to check if first element on the first list is on the second list, and if not then check recursively if something in the rest of the first list is in the second list:
(define (check-list list1 list2)
(cond ((null? list1) #f)
((memq (car list1) list2) #t)
(else (check-list (cdr list1) list2))))
Here's an answer using higher-order functions
in mit-schme
(define (check-list L1 L2)
(apply boolean/or (map (lambda (x) (member? x L2)) L1)))
(define remove-item
(lambda (lst ele)
(if (null? lst)
'()
(if (equal? (car lst) ele)
(remove-item (cdr lst) ele)
(cons (car lst)
(remove-item (cdr lst) ele))))))

(Scheme) Find out if some of the numbers in a list add up to a certain number?

I'm making a program that takes a list and a sum. If some of the numbers in the list add up to the sum, it returns true. Else, return false. It seems to be working for some cases but not for others. For example,
if I input this:
(numlist-sum '(5 9) 9)
It should return true because one of the numbers (9) equals the sum (9). But, for some reason, its returning false.
I can't figure out what the problem is. Help please?
(define (numlist-sum? ls sum)
(if (null? ls) #t
(if (and (null? (cdr ls)) (equal? (car ls) sum)) #t
(if (equal? (car ls) sum) #t
(if (equal? (cdr ls) sum) #t
(if (equal? (apply + (car ls) (cdr ls)) sum) #t
#f))))))
I'll give you some hints for solving this problem (looks like homework). First write a procedure that generates all the possible subsets of the list (e.g., the power set of the list). For example:
(powerset '(1 2 3))
=> '(() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3))
With the above procedure in hand (and it's easy to find the algorithm, Google is your best friend), simply iterate over each of the sublists and sum its values:
(apply + '(2 3))
=> 5
If one of the sublists' sum equals the expected value, return #t. If none of the sums satisfy the expected value, return #f.
EDIT:
I forgot to mention, this is a well-known problem - it's the subset sum problem, which can be efficiently solved (at least, more efficiently than generating the power set) using dynamic programming. But I don't think that's the goal of this homework in particular.
Here is a solution that checks each element one by one and then recurses down the list if the first element isn't the sum.
(define (numlist-sum list sum)
(and (not (null? list))
(let ((head (car list)))
(cond ((number? head)
(or (= sum head)
(numlist-sum (cdr list) sum)))
((list? head)
(or (= sum (apply + head))
(numlist-sum (cdr list) sum)))
(else 'ill-formed-list)))))
Also, note that your code can be rewritten as:
(define (numlist-sum? ls sum)
(or (null? ls)
(if (and (null? (cdr ls)) (equal? (car ls) sum))
(equal? (car ls) sum)
(equal? (cdr ls) sum)
(equal? (apply + (car ls) (cdr ls)) sum)))
I'd say the use of '(if pred #t else ...) is a bit awkward and hides the true logic of the code.

SCHEME - Writing my own append produces a weird result

I want to write my own append , for appending an element to an existing list .
I've written the following :
(define (appendElem llist elem)
(if (null? llist)
elem
(cons (car llist) (appendElem (cdr llist) elem))))
But when I do this :
(appendElem (list 1 2 30) 11)
I get :
(1 2 30 . 11)
So the question is , why (1 2 30 . 11) and not (1 2 30 11) ?
Thanks
EDIT:
Fixed :
(define (appendElem llist elem)
(if (null? llist)
(list elem)
(cons (car llist) (appendElem (cdr llist) elem))))
Think about what you want your base case to be. Do you want just elem, or do you want a list with the single item elem? There is a difference. If the want the latter, you will need to fix your base case in the code.
In other words, do you want (appendElem '() 42) to return 42, or (42)? Think carefully about the answer to that question, then think about what the consequence of each choice is.
By the way, while you can implement appendElem as a toy, you'll soon realise that that function has O(n) runtime. So do not build lists using this approach! The standard way to build a list is to cons items to it, then reverse the final resulting list.
Here is the answer :
(define (appendElem llist elem)
(if (null? llist)
(list elem)
(cons (car llist) (appendElem (cdr llist) elem))))
Thanks to #Chris Jester-Young .
Another suggestion for you:
(define (make-dl ls) ; turn a list into a difference list
(cons ls (last-pair ls)))
(define (snoc-dl! dl e) ; snoc ~ appendElem, destructively
(set-cdr! (cdr dl) (list e))
(set-cdr! dl (cddr dl)))
(define (dl-list dl) ; get the list back
(car dl))
for an O(1) appending at list's end (well, calling make-dl will be O(n), but all the subsequent appends will take O(1) time).