scheme : What's imperative features? - scheme

The bottom code is to remove adjacent duplicate elements from a sorted list L.
(define a
(lambda (L)
(cond
((null? L) L)
((null? (cdr L)) L)
((eqv? (car L) (car (cdr L))) (a (cdr L)))
(else (cons (car L) (a (cdr L)))))))
Question is "Write a similar function that uses the imperative features of Scheme to modify L 'in place,' rather than building a new list. Compare that to the code above in terms of brevity, conceptual clarity, and speed.
But I don't understand clearly what imperative features. Plz help.

The question asks for you to use some or all of the following procedures to write the solution: set-car!, set-cdr!, set!, etc. In this context, the imperative features refer to those Scheme procedures that mutate data - using them you can modify a list structure "in place", meaning: without creating a new list, instead directly modifying the list passed as parameter.
Notice that all the procedures' names mentioned end with a ! (pronounced: bang!), this is to warn the programmer that they will change the object received as parameter. Contrast this with the procedures you've been using up until now, that won't change the object and if necessary will return a new object with the requested modification - a functional programming style, unlike the imperative programming style that will happen when you start using bang!-procedures.
Take a look at section 3.3 Modeling with Mutable Data in the SICP book, it will explain in detail how to deal with operations that mutate data.

Related

Is there a limit to how many car and cdr we can chain in Scheme?

Some answers on here just say that you can chain multiple car and cdr to reduce the clutter they create so, you could use (cadr (list)) instead of (car (cdr (list) )), but I have tried chaining multiple car and cdr and sometimes it will stop working on like the 5th one or something, I tried googling if there is a limit or something but couldnt find any answers.
specifically my problem shows here -> trying to get 7 from a list only using car and cdr.
list is (1(2(3(4(5(6(7)))))))))
(display (car(car(cdr(car(cdr(car(cdr(car(cdr(car (cdr (car (cdr '(1(2(3(4(5(6(7)))))))))))))))))))))
-> shows 7
(display (caadadadadadadr '(1(2(3(4(5(6(7)))))))))
-> shows error
Is this not how this works?
You aren't specific about which Scheme you're using. But for every Scheme implementation I'm aware of, there's a limit to how many car/cdr compositions are provided. In R5RS, for example, we see
library procedure: cddddr pair
These procedures are compositions of
car and cdr, where for example caddr could be defined by
(define caddr (lambda (x) (car (cdr (cdr x))))).
Arbitrary compositions, up to four deep, are provided. There are
twenty-eight of these procedures in all.

Filtering a list with indexes MIT-scheme

Is there a good way to filter a list using each element and its index in scheme? This is how I'm doing it now, but it seems overly complex
(map cdr
(filter (lambda (index-and-element)
(filter-proc (car index-and-element)
(cdr index-and-element)))
(map cons (iota (length l))
l)))
Looks perfectly fine to me. Except, perhaps you meant map cdr...
Personally I like very short variable names whenever possible, so instead of index-and-element I'd just use ie -- they are unimportant, it's just some wiring, so make them as invisible as possible.
Another possibility is to use (map list ...) initially, not (map cons ...), and then inside the lambda to use (apply filter-proc ie). this way filter-proc is called with two arguments, so it can be defined (define (filter-proc idx elt) ...).
And after all that, since it is indeed complex and error-prone to type all this anew each time, we'd just define a higher-order function for this so it is easier to use, like
(define (indexed-filter ipred lst)
(filter (lambda (ie)
(apply ipred ie))
(map list (iota (length lst))
lst)))
;; (define (ipred idx elt) ....) ; returns Bool
and use it whenever the need arises.
I've intentionally left out the (map cadr ...) post-processing step, since you could sometimes want to get the indices of the matching elements instead of the elements themselves. So that would be part of the calling "protocol" so to speak -- whether you're interested in indices, elements, or both, you'd just tweak the call to this general procedure.

Can any case of using call/cc be rewritten equivalently without using it?

Can any case of using call/cc be rewritten equivalently without using it?
For example
In (g (call/cc f)), is the purpose of f to evaluate the value of
some expression, so that g can be applied to the value?
Is (g (call/cc f)) always able to be rewritten equivalently
without call/cc e.g. (g expression)?
In ((call/cc f) arg), is the purpose of f to evaluate the
definition of some function g, so that function g can be
applied to the value of arg?
Is ((call/cc f) arg) always able to be rewritten equivalently
without call/cc e.g. (g arg)?
If the answers are yes, why do we need to use call/cc?
I am trying to understand the purpose of using call/cc, by contrasting it to not using it.
The key to the direct answer here is the notion of "Turing equivalence". That is, essentially all of the commonly used programming languages (C, Java, Scheme, Haskell, Lambda Calculus etc. etc.) are equivalent in the sense that for any program in one of these languages, there is a corresponding program in each of the other languages which has the same meaning.
Beyond this, though, some of these equivalences may be "nice" and some may be really horrible. This suggests that we reframe the question: which features can be rewritten in a "nice" way into languages without that feature, and which cannot?
A formal treatment of this comes from Matthias Felleisen, in his 1991 paper "On the Expressive Power of Programming Languages" (https://www.sciencedirect.com/science/article/pii/016764239190036W), which introduces a notion of macro expressibility, pointing out that some features can be rewritten in a local way, and some require global rewrites.
The answer to your original question is obviously yes. Scheme is Turing-complete, with or without call/cc, so even without call/cc, you can still compute anything that is computable.
Why "it is more convenient than writing the equivalent expression using lambda"?
The classic paper On the Expressive Power of Programming Languages by Matthias Felleisen gives one answer to this question. Pretty much, to rewrite a program with call/cc to one without it, you might potentially need to transform your whole program (global transformation). This is to contrast some other constructs that only need a local transformation (i.e., can be written as macro) to remove them.
The key is: If your program is written in continuation passing style, you don't need call/cc. If not, good luck.
I whole-heartedly recommend:
Daniel P. Friedman. "Applications of Continuations: Invited Tutorial". 1988 Principles of Programming Languages (POPL88). January 1988
https://cs.indiana.edu/~dfried/appcont.pdf
If you enjoy reading that paper, then check out:
https://github.com/scheme-live/bibliography/blob/master/page6.md
Of course anything that is written with call/cc can be written without it, because everything in Scheme is ultimately written using lambda. You use call/cc because it is more convenient than writing the equivalent expression using lambda.
There are two senses to this question: an uninteresting one and an interesting one:
The uninteresting one. Is there some computation that you can do with call/cc that you can't do in a language which does not have it?
No, there isn't: call/cc doesn't make a language properly more powerful: it is famously the case that a language with only λ and function application is equivalent to a universal Turing machine, and thus there is no (known...) more powerful computational system.
But that's kind of uninteresting from the point of view of programming-language design: subject to the normal constraints on memory &c, pretty much all programming languages are equivalent to UTMs, but people still prefer to use languages which don't involve punching holes in paper tape if they can.
The interesting one. Is it the case that call/cc makes some desirable features of a programming language easier to express?
The answer to this is yes, it does. I'll just give a couple of examples. Let's say you want to have some kind of non-local exit feature in your language, so some deeply-nested bit of program can just say 'to hell with this I want out', without having to climb back out through some great layer of functions. This is trivial with call/cc: the continuation procedure is the escape procedure. You can wrap it in some syntax if you want it to be nicer:
(define-syntax with-escape
(syntax-rules ()
[(_ (e) form ...)
(call/cc (λ (e) form ...))]))
(with-escape (e)
... code in here, and can call e to escape, and return some values ...)
Can you implement this without call/cc? Well, yes, but not without either relying on some other special construct (say block and return-from in CL), or without turning the language inside out in some way.
And you can build on things like this to implement all sorts of non-local escapes.
Or, well, let's say you want GO TO (the following example is Racket):
(define (test n)
(define m 0)
(define start (call/cc (λ (c) c)))
(printf "here ~A~%" m)
(set! m (+ m 1))
(when (< m n)
(start start)))
Or, with some syntax around this:
(define-syntax-rule (label place)
(define place (call/cc identity)))
(define (go place)
(place place))
(define (horrid n)
(define m 0)
(label start)
(printf "here ~A~%" m)
(set! m (+ m 1))
(when (< m n)
(go start)))
So, OK, this perhaps is not a desirable feature of a programming language. But, well, Scheme doesn't have GO TO right, and yet, here, it does.
So, yes, call/cc (especially when combined with macros) makes a lot of desirable features of a programming language possible to express. Other languages have all these special-purpose, limited hacks, Scheme has this universal thing from which all these special-purpose hacks can be built.
The problem is that call/cc doesn't stop with the good special-purpose hacks: you can also build all the awful horrors that used to blight programming languages out of it. call/cc is like having access to an elder god: it's really convenient if you want dread power, but you'd better be careful what comes with it when you call, because it may well be an unspeakable horror from beyond spacetime.
An easy use of call/cc is as a bail out. eg.
;; (1 2) => (2 4)
;; #f if one element is not a number
(define (double-numbers lst)
(call/cc
(lambda (exit)
(let helper ((lst lst))
(cond ((null? lst) '())
((not (number? (car lst))) (exit #f))
(else (cons (* 2 (car lst)) (helper (cdr lst)))))))))
So to understand this. If we are doing (double-numbers '(1 2 r)) the result is #f, but the helper has done (cons 1 (cons 2 (exit #f)))
Without call/cc we see the continuation would be whatever called double-numbers since it actually return normally from it. Here is an example without call/cc:
;; (1 2) => (2 4)
;; #f if one element is not a number
(define (double-numbers lst)
(define (helper& lst cont)
(cond ((null? lst) (cont '()))
((not (number? (car lst))) #f) ; bail out, not using cont
(else (helper& (cdr lst)
(lambda (result)
(cont (cons (* 2 (car lst)) result)))))))
(helper& lst values)) ; values works as an identity procedure
I imagine it gets harder pretty quick. Eg. my generator implementation. The generator relies on having access to continuations to mix the generator code with where it's used, but without call/cc you'll need to do CPS in both the generator, the generated generator and the code that uses it.

Scheme program to turn every element of a list into atoms

I need a program that takes a list as input and turns every element found in the list into atoms. Here's what i have so far but i keep running into errors.
(define make-lat
(lambda (l)
(cond
((null? l) (quote ()))
(else
(cond
((list? (car l))
(cons (caar l)
make-lat (cdr l)))
(else
((atom? (car l))
(cons (car l)
(make-lat(cdr l)
)))))))))
Can someone help me out?
Your code looks a little disorganized to me, and I think you might want to think about following the steps in the How To Design Programs Design Recipe:
Step one: can you write a purpose statement for your program? It should say what the function does.
Step two: can you write a contract? It should say what kind of data the program takes in, and
what it produces. You've got to be specific, here, and any kind of data that you specify must either be built-in or have an explicit "data definition".
Step three: write some test cases! Provide a sample input, and the output that you expect.
For more design recipe goodness, check out How To Design Programs.
Your question looks like homework.
Here's a couple of things you could do to try and debug.
Use the Repl to try out parts of the function. E.g if in a cond, you are checking for null, you could do it on the REPL too.
(null? '(1 2 3)) or (null? '())
Check individual S-Exps. Are you sure that every function that you call has an opening and closing parens.
As a tip, simplify your cond's. You don't need to nest conds. You can put all conditions one by one.

Removing all duplicate members from a list in scheme

I am trying to remove duplicates in a list, using recursion. This is what I have. It only removes the first duplicate, not all of them.
My idea is to look at the first member, check if its a member of the rest of the list, if so, call the function again. If not, create a list with the first member and the result from calling the function again. I don't understand why it doesn't remove all the duplicates.
(define (removeDupes L)
(cond ((null? L) ())
((list? (member (car L) (cdr L))) removeDupes (cdr L))
(#T (cons ((car L) (removeDupes (cdr L)))))))
This is what I modified it to, and it works!! And I understand what was wrong with the cons. It needs two parameters and I only gave it one. I still have no Idea why the third line did not work....
(define (removeDupes L)
(cond ((null? L) ())
((list? (member (car L) (cdr L)))(removeDupes(cdr L)))
(#T (cons (car L) (removeDupes (cdr L))))))
There are multiple errors in your code, but the one that's probably causing the problem you've reported here is that your parentheses are wrong in the third line. You're trying to call removeDupes but your code doesn't actually do so; instead the value in that case ends up being (cdr L). Can you see why?
When you fix this, you'll find that your code starts producing errors. For the one you're likely to encounter first: take a careful look at how you're invoking cons on the last line. For the one you're likely to encounter next: remember that () is not self-evaluating in Scheme.
(I think this sort of thing is much harder to miss if you take care with the spacing and layout of your code. Put spaces between the elements of every list, for instance. Until you get so familiar with this stuff that these mistakes stop happening, you might want to make a habit of checking the parentheses any time you run across a mysterious error: have you missed a ( at the start of an expression, or put an extra ( before the arguments of a function, or forgotten the extra level of parens round a cond clause, or etc. etc. etc. Don't worry: after a while it'll stop happening...)

Resources