Passing a list as a Parameter in Scheme - scheme

I am a beginner to functional programming and I want to be able to read values from a console into a list, pass that list as a parameter, and then return the sum of the list in Scheme.
I want to get this result: (display (sum-list-members '(1 2 3 4 5))) but the user must enter these values at the console.
This is what I am working on:
(begin
(define count 0)
(define sum-list-members
(lambda (lst)
(if (null? lst)
0
(+ (car lst) (sum-list-members (cdr lst))))))
(display "Enter a integer [press -1 to quit]: ")
(newline)
(let loop ((i 0))
(define n(read))
(sum-list-members (list n))
(set! count i)
(if (not(= n -1))
(loop (+ i 1)))
)
(newline)
)

Using chicken-scheme, I'd do it like this:
(define (read-number-list)
(map string->number (string-tokenize (read-line))))
Define your sum-list-members as such:
(define (sum-list-members lst)
(fold + 0 lst))
To get string-tokenize to work, you might have to use a certain srfi. Fold is pretty much the same thing as you wrote, except that it's a function that takes a function and initial value as parameters.
The function has to receive 2 parameters, the first parameter is the current value and the second parameter is the value returned by the previous call or the initial value.

(do ((mlist () (cons n mlist))(n (read)(read)))
((= n -1) (display (apply + mlist))))

Related

User input to a list

I'm trying to take in user input and add it to a list but I have not been able to get it working. I'm still new to scheme and have been browsing around to try to figure it out but I haven't had any luck.
(display "Continue to enter numbers until satisfied then enter e to end")
(newline)
(define (intlist number)
(define number(read-line))
(cond (number? number)
(cons lst (number))
(else
(display lst)
done')))
this is what I have so far. Any help or direction to where I can learn a bit more is appreciated.
Your solution is almost correct, but it doesn't work, because:
Variable lst doesn't exist and with this expression (number), you are calling some undefined function number.
done' is badly written 'done.
Function cons expects element as first argument and other element or list as second argument.
See these examples:
> (cons 1 2)
'(1 . 2)
> (cons 1 '())
'(1)
> (cons 1 (cons 2 (cons 3 '())))
'(1 2 3)
Last example is important here- your function will be recursive and it will return a cons cell in each step. If I will follow your solution, this can be enough:
(define (list-from-user)
(let ((number (read)))
(if (number? number)
(cons number (list-from-user))
'())))
(Note that I used read instead of read-line, because read-line returns string, and let instead of define.)
If you really want to wait for e, you must decide, what happens if user enters something that isn't number and isn't e- maybe just ignore it?
(define (list-from-user)
(let ((user-input (read)))
(cond ((number? user-input) (cons user-input (list-from-user)))
((eq? user-input 'e) '())
(else (list-from-user)))))
Then just add some wrapping function with output:
(define (my-fn)
(begin (display "Continue to enter numbers until satisfied then enter e to end")
(newline)
(list-from-user)))
and call it
> (my-fn)
Note that my function returns list with numbers, instead of some useless 'done, so I can use that function in other functions.
(define (sum-of-list)
(let ((lst (my-fn)))
(format "Sum of given list is ~a." (apply + lst))))
> (sum-of-list)

Scheme program to get average not recognizing last number

I've created this super simple program to take a list from the console and return the average. For whatever reason I always get an error message saying the last number of the list is not a number. Here's my code:
(define getline (lambda ()
(read-line (current-input-port))
)
)
(define getlist (lambda ()
(let ((input (getline)))
(if (not (equal? input "end"))
(cons input (getlist))
' ()
)
)
)
)
(define x (getlist))
(define (sum x)
(if (null? x)
0
(+ (car x) (sum (cdr x)))))
(define (average x)
(/ (sum x) (length x)))
(display (average x) (current-output-port))
You don't mention what scheme implementation you're using, but read-line functions usually return a string. You have to convert those strings to numbers first to be able to add them:
(define x (map string->number (getlist)))
or else
(define (sum x)
(if (null? x)
0
(+ (string->number (car x)) (sum (cdr x)))))
or something else along those lines.

Outputting a sorted list of pairs in scheme recursively (issue with base case)

I want to sort and print out a list somewhat like this:
Apple : 1
Banana : 2
...etc (each pair is on a new line, but stackoverflow shows it like this)
I find that I can get it mostly done, but I get an error that it expects a pair, while it is given an empty list. I understand that the error is because I reached the end of my list, and that I need a base case here, but I'm not sure what is required. If I check to see if the list is null, and then return the list as my base case, it doesn't output anything.
Getting the following error:
car: contract violation expected: pair? given: ()
Thanks for checking out my problem.
(define lst '( ("Apple" 1) ("Orange" 4) ("Pear"3) ("Banana" 2)) )
(define name (lambda (m)
(car m)
))
(define priority (lambda (m)
(car (cdr m))
))
(define sortList
(lambda (lst)
(sort lst
(lambda (x y)
(<(priority x)(priority y))
)
)
)
)
(define printItem (lambda (m)
(display (name m))
(display " : ")
(display (priority m))
(display "\n")
)
)
(define printQueue
(lambda (lst)
(printItem (car(sortList lst)))
(printQueue (cdr (sortList lst)))
)
)
(printQueue lst)
You must ensure that the list is not empty for the procedure to work, that's the base case. Also avoid sorting the list twice at every iteration! try this:
(define printQueue
(lambda (lst)
(unless (null? lst)
(printItem (car lst))
(printQueue (cdr lst)))))
(printQueue (sortList lst))
By the way, it'd be more idiomatic to use a for-each in this case:
(define (printQueue lst)
(for-each printItem lst))

Scheme - How do I return a function?

This function is displaying the correct thing, but how do I make the output of this function another function?
;;generate an Caesar Cipher single word encoders
;;INPUT:a number "n"
;;OUTPUT:a function, whose input=a word, output=encoded word
(define encode-n
(lambda (n);;"n" is the distance, eg. n=3: a->d,b->e,...z->c
(lambda (w);;"w" is the word to be encoded
(if (not (equal? (car w) '()))
(display (vtc (modulo (+ (ctv (car w)) n) 26)) ))
(if (not (equal? (cdr w) '()))
((encode-n n)(cdr w)) )
)))
You're already returning a function as output:
(define encode-n
(lambda (n)
(lambda (w) ; <- here, you're returning a function!
(if (not (equal? (car w) '()))
(display (vtc (modulo (+ (ctv (car w)) n) 26))))
(if (not (equal? (cdr w) '()))
((encode-n n)(cdr w))))))
Perhaps a simpler example will make things clearer. Let's define a procedure called adder that returns a function that adds a number n to whatever argument x is passed:
(define adder
(lambda (n)
(lambda (x)
(+ n x))))
The function adder receives a single parameter called n and returns a new lambda (an anonymous function), for example:
(define add-10 (adder 10))
In the above code we created a function called add-10 that, using adder, returns a new function which I named add-10, which in turn will add 10 to its parameter:
(add-10 32)
=> 42
We can obtain the same result without explicitly naming the returned function:
((adder 10) 32)
=> 42
There are other equivalent ways to write adder, maybe this syntax will be easier to understand:
(define (adder n)
(lambda (x)
(+ n x)))
Some interpreters allow an even shorter syntax that does exactly the same thing:
(define ((adder n) x)
(+ n x))
I just demonstrated examples of currying and partial application - two related but different concepts, make sure you understand them and don't let the syntax confound you.

programmatic way to stop a function after certain time and debug enclosed variables

A long-run function like infinite loop:
> (define appendInf
(lambda (lst)
(appendInf (cons 1 lst)))
In Chez Scheme, make-engine can achieve the stopping after ticks:
> (define eng
(make-engine
(lambda ()
(appendInf '()))))
While of course with the scope of lst I get error when:
> (eng 50
list
(lambda (new-eng)
(set! eng new-eng)
(length lst)))
Exception: variable lst is not bound
If I want to get the value 'lst' in appendInf when the time limit is reached, I use set!:
> (define lst '())
> (define appendInf
(lambda (ls)
(set! lst (cons 1 ls))
(appendInf lst)))
now I can get:
> (eng 50
list
(lambda (new-eng)
(set! eng new-eng)
(length lst)))
8
So for every variable within the function I want to trace, a global variable needs to be added, and one more transforming by adding (set!…).
is this a correct way to handle any enclosed variables?
if yes to 1, in Scheme is there a better way to achieve this?
is there any programming language that can more easily
implement this kind of debugging?
Well. I'm using racket and it has a pretty good debugger and does standard r6rs as well as non-standard racket.
;; macro to do the heavy work
(define-syntax recdb
(syntax-rules ()
((_ thunk fun a1 ...)
(let ((orig-fun fun)(ethunk thunk))
(fluid-let ((fun (lambda args
(if (ethunk)
(apply orig-fun args) ;; set breakpoint on this
(apply orig-fun args)))))
(fun a1 ...))))))
;; a time-thunk generator
(define (period-sec sec)
(let ((time-done (+ sec (current-seconds))))
(lambda ()
(if (< time-done (current-seconds))
(begin
(set! time-done (+ sec (current-seconds)))
#t)
#f))))
;; a round-thunk generator
(define (rounds n)
(let ((rounds-to-go n))
(lambda ()
(if (zero? rounds-to-go)
(begin
(set! rounds-to-go (- n 1))
#t)
(begin
(set! rounds-to-go (- rounds-to-go 1))
#f)))))
;; my never ending procedure
(define (always n)
(always (+ n 1)))
;; one of the ones below to implement
(recdb (rounds 10) always 0))
(recdb (period-sec 1) always 0)
;; functions with auxillary procedures need to have their gut changed for it to work
(define (fib n)
(define (fib-aux n a b)
(if (= n 0)
a
(fib-aux (- n 1) b (+ a b))))
(recdb (period-sec 2) fib-aux n 0 1))
;; trying it
(fib 200000)
Now. Just run the debugger and set breakpoint (right click expression in the macro and choose "Pause at this point") where it's indicated in the code and you have a way to examine the variables every x seconds or x times.
Happy debugging :)

Resources