It's been a few months since I've touched Scheme and decided to implement a command line income partitioner using Scheme.
My initial implementation used plain recursion over the continuation, but I figured a continuation would be more appropriate to this type of program. I would appreciate it if anyone (more skilled with Scheme than I) could take a look at this and suggest improvements. I'm that the multiple (display... lines is an ideal opportunity to use a macro as well (I just haven't gotten to macros yet).
(define (ab-income)
(call/cc
(lambda (cc)
(let
((out (display "Income: "))
(income (string->number (read-line))))
(cond
((<= income 600)
(display (format "Please enter an amount greater than $600.00~n~n"))
(cc (ab-income)))
(else
(let
((bills (* (/ 30 100) income))
(taxes (* (/ 20 100) income))
(savings (* (/ 10 100) income))
(checking (* (/ 40 100) income)))
(display (format "~nDeduct for bills:---------------------- $~a~n" (real->decimal-string bills 2)))
(display (format "Deduct for taxes:---------------------- $~a~n" (real->decimal-string taxes 2)))
(display (format "Deduct for savings:-------------------- $~a~n" (real->decimal-string savings 2)))
(display (format "Remainder for checking:---------------- $~a~n" (real->decimal-string checking 2))))))))))
Invoking (ab-income) asks for input and if anything below 600 is provided it (from my understanding) returns (ab-income) at the current-continuation. My first implementation (as I said earlier) used plain-jane recursion. It wasn't bad at all either but I figured every return call to (ab-income) if the value was below 600 kept expanding the function.
(please correct me if that apprehension is incorrect!)
First of all, you don't need a continuation. According to the standard, Scheme will always perform tail call optimization. A tail call is a function call which is in the final position in a function; after that call is run, nothing else will happen. In that situation, we don't need to preserve the activation record we're currently in; as soon as the function we call returns, we'll just pop it. Consequently, a tail call reuses the current activation record. As an example, consider this:
(define (some-function x y)
(preprocess x)
(combine (modified x) y))
(some-function alpha beta)
When we call some-function, we allocate space for its activation record on the stack: local variables, parameters, etc. We then call (preprocess x). Since we need to return to some-function and keep processing, we have to preserve some-function's activation record, and so we push a new activation record on for preprocess. Once that returns, we pop preprocess's stack frame and keep going. Next, we need to evaluate modified; the same thing has to happen, and when modified returns, its result is passed to combine. One would think we'd need to create a new activation record, run combine, and then return this to some-function—but some-function doesn't need to do anything with that result but return it! Thus, we overwrite the current activation record, but leave the return address alone; when combine returns, then, it will return its value to exactly what was waiting for it. Here, (combine (modified x) y) is a tail call, and evaluating it doesn't require an extra activation record.
This is how you can implement loops in Scheme, for instance:
(define (my-while cond body)
(when (cond)
(body)
(my-while cond body)))
(let ((i 0))
(my-while (lambda () (< i 10))
(lambda () (display i) (newline) (set! i (+ i 1)))))
Without tail call optimization, this would be inefficient, and would potentially overflow with a long-running loop building up lots of calls to my-while. However, thanks to tail call optimization, the recursive call to my-while cond body is a jump, and allocates no memory, making this as efficient as iteration.
Secondly, you don't need any macros here. While you can abstract out the display block, you can do this with a plain function. Macros allow you, on some level, to change the syntax of the language—add your own sort of define, implement some type-case construct which doesn't evaluate all its branches, etc. Of course, it's all still s-expressions, but the semantics are no longer simply "evaluate the arguments and call the function". Here, however, function-call semantics are all you need.
With that said, I think this is how I'd implement your code:
(require (lib "string.ss"))
(define (print-report width . nvs)
(if (null? nvs)
(void)
(let ((name (car nvs))
(value (cadr nvs)))
(display (format "~a:~a $~a~n"
name
(make-string (- width (string-length name) 2) #\-)
(real->decimal-string value 2)))
(apply print-report width (cddr nvs)))))
(define (ab-income)
(display "Income: ")
(let ((income (string->number (read-line))))
(if (or (not income) (<= income 600))
(begin (display "Please enter an amount greater than $600.00\n\n")
(ab-income))
(begin (newline)
(print-report 40 "Deduct for bills" (* 3/10 income)
"Deduct for taxes" (* 2/10 income)
"Deduct for savings" (* 1/10 income)
"Remainder for checking" (* 4/10 income))))))
First, at least in my version of mzscheme, I needed a (require (lib "string.ss")) line to import real->decimal-string. Next, I abstracted out the display block you were talking about. What we see is that each line wants to print the money in the same format at the 40th column, printing a tag name and a row of dashes in front of it. Consequently, I wrote print-report. The first argument is the initial width; in this case, 40. The remaining arguments are field-value pairs. The length of each field (plus two for the colon and the space) are subtracted from the width, and we generate a string consisting of that many dashes. We use format to lay the fields out in the right order, and display to print the string. The function recurses over all the pairs (using tail recursion, so we won't blow the stack).
In the main function, I moved the (display "Income: ") to before the let; you ignore its result, so why assign it to a variable? I then augmented the if condition to test if input is false, which happens when string->number can't parse the input. Finally, I removed your local variables, since all you do is print them, and used Scheme's fraction syntax instead of division. (And of course, I use print-report instead of displays and formats.)
I think that's all; if you have any other questions about what I did, feel free to ask.
Related
I came across something that I can not understand.
#lang scheme
(define cc #f)
(define (val!)
(call/cc
(lambda (k)
(set! cc k)
0)))
(* 10 (val!))
(cc 100)
So far so good; the continuation of (* 10 []) is stored in cc and if we call (cc 100) we see 1000 in the REPL as expected.
But the next thing I tried was to define a variable to be the result of running the continuation:
(define x (cc 20))
I see 200 as a result in the REPL, but x does not get defined.
Does the continuation stored in cc include its returning so that the call to define never returns and instead the evaluation is the result of (* 10 val)? What is going on?
It returns nothing, because it does not return. (cc 20), just as (cc 100), does not return a value to its caller. cc is not a function, it is a continuation - it remembers where to return / "feed" its value, by itself.
(define x (cc 20))
means, approximately, in pseudocode,
(let ([val (cc 20)])
(primitive-define-top-level-var! "x" val))
but (cc 20) bypasses the setting of val and using it to define x, and returns directly to the top level, as was done by the original captured continuation.
Does the continuation stored in cc include its returning ["destination" -- wn] so that the call to define never returns and instead the evaluation is the result of (* 10 val)?
Yes.
What is going on?
Exactly that.
edit:
Loading the following in DrRacket,
#lang scheme
(define cc #f)
(define (val!)
(call/cc
(lambda (k)
(set! cc k)
0)))
(* 10 (val!))
(cc 100)
(display "Good!\n")
(define x (cc 20))
(display "Shucks!\n")
I even get an error message explaining what is going on:
Language: scheme, with debugging; memory limit: 128 MB.
0
1000
Good!
200
define-values: skipped variable definition;
cannot continue without defining variable
variable: x
in module: 'anonymous-module
>
What's going on?
There are two types of continuations.
A continuation produced by call/cc never returns a value to its caller. See Will Ness's answer for more on that.
But the continuations produced by call-with-composable-continuation are composable continuations, which do return values.
The solution
If you want a continuation to return a value to its caller, you should use a composable continuation, by setting up a prompt and using call-with-composable-continuation.
You can define a kind of prompt:
(define my-prompt
(make-continuation-prompt-tag 'my-prompt))
And use the prompt in call-with-composable-continuation to specify that you only want to capture the continuation starting from the prompt.
(define cc #f)
(define (val!)
(call-with-composable-continuation
(lambda (k)
(set! cc k)
0)
my-prompt))
Then you just have to put the prompt wherever you want the continuation to start before you call val! to save it.
;; the prompt specifies that it's `(* 10 [])`, and not something larger
(call-with-continuation-prompt
(λ () (* 10 (val!)))
my-prompt)
Then, since this continuation has a clear "end" defined by the prompt, it can return a value when it reaches that end.
(define x (cc 20))
; defines x as 200
See also: What exactly is a "continuation prompt?"
I am trying to programmatically increment a purely alphabetical string in Scheme.
Like this "MA", then "MB" and when it reaches "MZ", it should become "MAA" and so on till "MZZ" and then it should become "MAAA" and so on.The "M" needs to be added as a prefix for the kind of work that I am doing.
I looked at this question: Incrementing alphabets and this is exactly what I want.
However, I have absolutely no idea from where to start. For starters I am not even sure how to handle ASCII in scheme. I am not expecting the whole code, but I would appreciate it if I got a few hints.
Here's my implementation. Note that you need to load SRFI 1, which provides unfold-right:
(define letters "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
(define (number->letters num)
(unfold-right negative?
(lambda (i) (string-ref letters (remainder i 26)))
(lambda (i) (- (quotient i 26) 1))
num))
(define (number->tag num)
(list->string (cons #\M (number->letters num))))
Examples:
> (number->tag 0)
"MA"
> (number->tag 18277)
"MZZZ"
> (number->tag 18278)
"MAAAA"
The OP asked for an explanation of what the code does. So, with the understanding that the OP already understands the algorithm (since they linked to it already), what's basically left is the unfold operation.
Fold and unfold are a bit lengthy to explain and I don't want to derail this post by explaining them, but it's possible to "expand" the unfold into the equivalent loop (using the same variable names as the SRFI 1 reference implementation of unfold-right) to express what's going on:
(define (number->letters num)
(let lp ((seed num) (ans '()))
(if (negative? seed)
ans
(lp (- (quotient seed 26) 1)
(cons (string-ref letters (remainder seed 26)) ans)))))
Basically, it builds a list, from right to left, using (string-ref letters (remainder seed 26)) each iteration (where seed is num in the initial iteration). seed's value is then updated to (- (quotient seed 26) 1) for the next iteration. The list stops when (negative? seed) is true.
You might then ask why one would use an unfold instead of the loop. Basically, in functional programming, when a "concept" can be expressed in higher-level terms (e.g., for-each, map, filter, fold, or unfold), using those terms helps other programmers understand what the code does. It's a bit like "design patterns" (as commonly used in object-oriented programming), within a functional programming context. :-)
In an effort to find a simple example of CPS which doesn't give me a headache , I came across this Scheme code (Hand typed, so parens may not match) :
(define fact-cps
(lambda(n k)
(cond
((zero? n) (k 1))
(else
(fact-cps (- n 1)
(lambda(v)
(k (* v n))))))))
(define fact
(lambda(n)
(fact-cps n (lambda(v)v)))) ;; (for giggles try (lambda(v)(* v 2)))
(fact 5) => 120
Great, but Scheme isn't Common Lisp, so I took a shot at it:
(defun not-factorial-cps(n k v)
(declare (notinline not-factorial-cps)) ;; needed in clisp to show the trace
(cond
((zerop n) (k v))
((not-factorial-cps (1- n) ((lambda()(setq v (k (* v n))))) v))))
;; so not that simple...
(defun factorial(n)
(not-factorial-cps n (lambda(v)v) 1))
(setf (symbol-function 'k) (lambda(v)v))
(factorial 5) => 120
As you can see, I'm having some problems, so although this works, this has to be wrong. I think all I've accomplished is a convoluted way to do accumulator passing style. So other than going back to the drawing board with this, I had some questions: Where exactly in the Scheme example is the initial value for v coming from? Is it required that lambda expressions only be used? Wouldn't a named function accomplish more since you could maintain the state of each continuation in a data structure which can be manipulated as needed? Is there in particular style/way of continuation passing style in Common Lisp with or without all the macros? Thanks.
The problem with your code is that you call the anonymous function when recurring instead of passing the continuation like in the Scheme example. The Scheme code can easily be made into Common Lisp:
(defun fact-cps (n &optional (k #'values))
(if (zerop n)
(funcall k 1)
(fact-cps (- n 1)
(lambda (v)
(funcall k (* v n))))))
(fact-cps 10) ; ==> 3628800
Since the code didn't use several terms or the implicit progn i switched to if since I think it's slightly more readable. Other than that and the use of funcall because of the LISP-2 nature of Common Lisp it's the identical code to your Scheme version.
Here's an example of something you cannot do tail recursively without either mutation or CPS:
(defun fmapcar (fun lst &optional (k #'values))
(if (not lst)
(funcall k lst)
(let ((r (funcall fun (car lst))))
(fmapcar fun
(cdr lst)
(lambda (x)
(funcall k (cons r x)))))))
(fmapcar #'fact-cps '(0 1 2 3 4 5)) ; ==> (1 1 2 6 24 120)
EDIT
Where exactly in the Scheme example is the initial value for v coming
from?
For every recursion the function makes a function that calls the previous continuation with the value from this iteration with the value from the next iteration, which comes as an argument v. In my fmapcar if you do (fmapcar #'list '(1 2 3)) it turns into
;; base case calls the stacked lambdas with NIL as argument
((lambda (x) ; third iteration
((lambda (x) ; second iteration
((lambda (x) ; first iteration
(values (cons (list 1) x)))
(cons (list 2) x)))
(cons (list 3) x))
NIL)
Now, in the first iteration the continuation is values and we wrap that in a lambda together with consing the first element with the tail that is not computed yet. The next iteration we make another lambda where we call the previous continuation with this iterations consing with the tail that is not computed yet.. At the end we call this function with the empty list and it calls all the nested functions from end to the beginning making the resulting list in the correct order even though the iterations were in oposite order from how you cons a list together.
Is it required that lambda expressions only be used? Wouldn't a named
function accomplish more since you could maintain the state of each
continuation in a data structure which can be manipulated as needed?
I use a named function (values) to start it off, however every iteration of fact-cps has it's own free variable n and k which is unique for that iteration. That is the data structure used and for it to be a named function you'd need to use flet or labels in the very same scope as the anonymous lambda functions are made. Since you are applying previous continuation in your new closure you need to build a new one every time.
Is there in particular style/way of continuation passing style in
Common Lisp with or without all the macros?
It's the same except for the dual namespace. You need to either funcall or apply. Other than that you do it as in any other language.
For example, when I use the procedure printf on the list '((2 t r d)), the last line in my output is
'(#<void>)
and the number of times '(#<void>) appears depend on the number of list nested. Can you please explain this for me???
This is my printf function
(define counting
(lambda (lst)
(if (null? lst)
'()
(printf "~a, ~s\n" (car lst) (length (cdr lst))))))
I have try to other procedure like fprintf and using this form
(fprintf (current-output-port) "~a, ~s\n" (car lst) (length (cdr lst)))
Same thing happens!
AFAIK there is no such procedure in the Scheme standard so you might need to add a tag for a implementation that has it. I know racket has printf.
A (display x) (and (printf x) in racket) alone usually don't display so what produced (#<void>) is not in the question. In Scheme every procedure evaluates to a value. To illustrate this try doing:
(map display '(1 2 3 4))
Which will return a list with 4 unspecified values since map makes a list of the results. display (and printf in racket) prints the result of the evaluation of the argument but doesn't need to return anything since the standard doesn't say that is should. Most implementations do this by returning an undefined object, but some actually return the argument too. The main function of them is to do side effect of displaying something on screen and that it has done. for ignoring return values you can use for-each which is map just for side effects.
(for-each display '(1 2 3 4))
When that said in Scheme it's normal that every procedure return something and you misread output with the REPLs printing of the returned values.
You said that 'the last line of your output is '(#<void>) - this is occurring because your Scheme environment is displaying 1) what you want to be printed and 2) the returned value of the evaluated expression. For example
> (list (display 1))
1(#<void>)
The '1' is printed and then the list result is printed. Since you are typing in an interactive session you will always get the returned value displayed. You can't really hide the returned value however most Schemes will recognize a 'undefined' return value and not print it.
> (display 1)
1
In the above, even though display returns #<void> the interpreter knows not to show it.
I have tried to write a procedure that gets an integer as parameter and returns true if the number is a palindrome and false otherwise and it seems to be that there is a problem with changing a global parameter's value whithin an internal function block.
(define index 0)
(define (palindrome? x)
(if (= (lenght x) 1)
#t
(if (last_equal_first x)
(palindrome? (remove x))
#f)))
(define (lenght x)
(define index **(+ index 1))**
(if (= (modulo x (ten_power index)) x)
index
(lenght x)))
(define (last_equal_first x)
(if (= (modulo x 10) (modulo x (/ (ten_power (lenght x)) 10)))
#t
#f))
I would like to know what can I do about it
thanks!
Well, one problem is that you're redefining index after it's been used, in the length function. define doesn't really do what you want here - you want set!.
However, I think you'll find another bug when you try to call the length function more than once - you never set index to 0 after the first time, so I believe your length function will only work once.
However, this seems like it might be a homework assignment. Would you like clear instructions on fixing these problems, or would you like clues that lead you to understand the algorithm more?
What that (define ...) statement does in lenght is create a new variable called "index" that is more locally scoped than the "index" you defined at the top. That's only the superficial problem---more importantly, it looks like you're trying to write C code using Scheme. In a simple homework assignment like this, you should not need to use global variables, nor should you ever have to change a variable once it's created. Many programmers have trouble shifting how they think when first learning functional programming.
The way you've written lenght is not so much recursion as just a glorified while loop! There is no point to recursion if (lenght x) only calls (lenght x) again. For example, here's how I would write digits to count how many base-10 digits are in a number:
(define digits
(lambda (n)
(letrec ([digit-helper (lambda (n index)
(if (= (modulo n (expt 10 index)) n)
index
(digit-helper n (add1 index))))])
(digit-helper n 0))))
Notice how I never change a variable once it's been created, but only create new variables each time. Since I need to keep track of index, I created helper function digit-helper that takes two arguments to mask the fact that digit only takes one argument.