I'm trying to implement generators in racket using call/cc, I have this code so far
(define (foo2)
(define (g abort)
(define-syntax-rule
(yield x)
(call/cc (lambda (k)
(set! g k)
(abort x))))
(yield 'foo)
(yield 'bar)
(yield 'tar)
(abort 'end))
(thunk (call/cc g)))
If I play with this in the REPL it seems to be working correctly
foo.rkt> (define g (foo2))
foo.rkt> (g)
'foo
foo.rkt> (g)
'bar
foo.rkt> (g)
'tar
foo.rkt> (g)
'end
foo.rkt> (g)
'end
foo.rkt>
But if I try to call g inside a list, it hangs and I have no idea what is happening
foo.rkt> (define g (foo2))
foo.rkt> (list (g) (g) (g))
;; prompt is not released
What is going on? Where my generator implementation is wrong?
What is (list (g) (g) (g))? Well it is basically this in CPS:
(g& (lambda (g1) ; continuation g1
(g& (lambda (g2)
(g& (lambda (g3)
(list& g1 g2 g3 halt))))
You are replacing g&, but all of you yield share the same initial abort which is continuation g1 and you will never ever reach continuation g2 since every time abort is called you run continuation g1. If you step through you'll notice that this continuation gets fed all the yield values but eventually it calls abort. Even if you remove the last call it will always call the second (g) in your expression.
It helps to know call/cc& is this:
(define (call/cc& f cc)
(f (lambda (v ignored-cc)
(cc v))
cc))
Now g in CPS would look something like this. Notice the abort are free variables in there and they will be the same even if you replace g&
(define (g& abort cont)
(call/cc& (lambda (k cc)
(set!& g&
k
(lambda (undefined)
(abort 'foo cc))))
(lambda (ignored1)
(call/cc& (lambda (k cc)
(set!& g&
k
(lambda (undefined)
(abort 'bar cc))))
(lambda (ignored2)
(call/cc& (lambda (k cc)
(set!& g&
k
(lambda (undefined)
(abort 'tar cc))))
(lambda (ignored3)
(abort 'end cont)))))))))
As a fix I guess you need to control what you set as g. Eg. instead of
(set! g k) something like this perhaps:
(set! g (lambda (new-abort)
(set! abort new-abort)
(k 'ignored)))
Then the list expression works as expected. Why it worked in the REPL is due to continuation prompts.
Related
I'm trying to execute the following simple function inside racket repl:
(define (f x)
(let ((cont null))
(println (+ 10 (call/cc (lambda (cc)
(set! cont cc)
10))))
cont))
((f 1) 10)
this call inifinitely prints 20, while i'm expecting it to be printed at most twice (once for (f 1), and once for continuation procedure call)
How can you interpret this behavior?
update
however when assigned to some top-level var it works:
> (define kont (f 1))
;;=> 20
> (kont 12)
;;=> 22
Can't see what's the conceptual difference
I was looking for a way to repeat a function call a certain number of times and accumulate the results in a list and couldn't find anything in the standard library, so I wrote one. It's simple to write, but it seems like such an obvious thing that I feel like there must be an accepted way of doing this using standard library functions.
Here are the two functions I'm looking to replace:
(define (repeat n f)
(unless (<= n 0)
(f)
(repeat (sub1 n) f)))
(define (accumulate n f)
(let loop ([n n] [l empty])
(if (<= n 0)
l
(loop (sub1 n)
(cons (f) l)))))
Is there any simpler way of achieving this?
If your function does not any take arguments, you can use build-list
Example:
#lang racket
;; The function you want to call many times
(define (f)
#t)
;; Use build list with a lambda to wrap your function because
;; build-list want a function takin integer as its second argument
(build-list 5 (lambda (x) (f)))
result:
'(#t #t #t #t #t)
Edit: you can also define a function to wrap the lambda
(define (repeat-then-accumulate n f)
(build-list n (lambda (x) (f)))
)
Usage:
;; Using the f function defined earlier
(repeat-then-accumulate 10 f)
result:
'(#t #t #t #t #t #t #t #t #t #t)
Edit2: If you want to have fixed args, you could do something like
#lang racket
;; The function you want to call many times
(define (f a b)
(+ a b))
(define (repeat-then-accumulate n f args)
(build-list n (lambda (x) (apply f args)))
)
Usage:
(repeat-then-accumulate 10 f '(3 5))
Result:
'(8 8 8 8 8 8 8 8 8 8)
It looks like #AlexKnauth didn't feel like taking your internet points for his answer, and he phrased it as a comment. I'm not proud, though... Use racket's list comprehension form:
(for/list ([i (in-range n)]) (f i))
(I added an explicit "in-range", just to get better error-checking.)
For example,
(require racket/generator)
(define f add1)
(define init 0)
(in-producer (generator () (let loop ([x init]) (yield x) (loop (f x)))))
Is there any better way to do this? I don't quite like generators since they have hidden states.
Streams
Using streams is probably the easiest:
(require racket/stream)
;; X [X -> X] -> [Streamof X]
(define (repeated-fn-stream init f)
(stream-cons init (repeated-fn-stream (f init) f)))
(repeated-fn-stream 0 add1)
Sequences
Alternatively, using sequences and make-do-sequence:
(require racket/sequence)
;; X [X -> X] -> [Sequenceof X]
(define (repeated-fn-sequence init f)
;; A "Pos" is an X that's the result of applying f repeatedly to init
(define (pos->element pos) pos)
(define (next-pos pos) (f pos))
(define init-pos init)
(make-do-sequence
(λ ()
(values pos->element
next-pos
init-pos
#false
#false
#false))))
(repeated-fn-sequence 0 add1)
If you wanted to use sequences, and you wanted to use define-sequence-syntax to make for loops specialize it:
(this is completely unnecessary for "pure" functionality, but it may have different performance characteristics)
(require (for-syntax syntax/parse))
(define-sequence-syntax in-repeated-fn-sequence
(λ () #'repeated-fn-sequence) ; when used as a normal expression
(syntax-parser ; when used *directly* as a for-loop clause
[[(x) (_ init-expr f-expr)]
#'[(x) (:do-in
([(init) init-expr] [(f) f-expr])
#true
([x init])
#true
()
#true
#true
[(f x)])]]))
(for/list ([x (in-repeated-fn-sequence 0 add1)]
[i (in-range 10)])
x)
When using define-sequence-syntax, you should make sure that for everything there is a "single point of truth". Because of that you often see this pattern:
(define-sequence-syntax in-___
(λ () #'in-___/proc) ; when used as a normal expression
(syntax-parser
....everything that defines the actual functionality....))
;; This is completely determined by the sequence-syntax above,
;; that way there is NO duplicated functionality and NO chance for
;; it to get "out of sync".
(define (in-___/proc parameter ...)
(for/stream ([elem (in-___ parameter ...)])
elem))
What that means for this is that once you decide you want to use define-sequence-syntax, you should define the repeated-fn-sequence function in terms of it:
(define (repeated-fn-sequence init f)
(for/stream ([elem (in-repeated-fn-sequence init f)])
elem))
That way if the in-repeated-fn-sequence needs to be changed to fix a bug or switch representations, the function version changes with it automatically.
The best function for this job is an unfold… but unfortunately, Racket does not provide a built-in sequence-unfold or stream-unfold operation. However, there is a stream-unfold operation in the srfi/41 library, which will meet your needs. You can see this in action with the following program:
#lang racket
(require (only-in srfi/41 stream-unfold))
(define nats (stream-unfold identity (const #t) add1 0))
(for/list ([i (in-range 20)] [n nats]) n)
This produces the following output:
'(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
If you don’t want to use srfi/41, you can write stream-unfold yourself in terms of the racket/stream API without too much difficulty, and without any statefulness:
(define (stream-unfold mapper pred? gen base)
(let loop ([base base])
(if (pred? base)
(stream-cons (mapper base) (loop (gen base)))
empty-stream)))
My program is supposed to convert a given temperature from Fahrenheit to Centigrade or the other way around. It takes in a list containing a number and a letter. The letter is the temperature and the letter is the unit we are in. Then I call the appropriate function either F-to-C or C-to-F. How do I call the functions with the given list that was first checked in my temperature-conversion function. Here is my code.
(defun temperature-conversion (lst)
(cond
((member 'F lst) (F-to-C))
((member 'C lst) (C-to-F))
(t (print "You didn't enter a valid unit for conversion"))
)
)
(defun F-to-C ()
;;(print "hello")
(print (temperature-conversion(lst)))
)
(defun C-to-F ()
(print "goodbye"))
;;(print (temperature-conversion '(900 f)))
(setf data1 '(900 f))
You have infinite recursion: temperature-conversion calls F-to-C which calls temperature-conversion again.
I would do this:
(defun c2f (c) (+ 32 (/ (* 9 c) 5)))
(defun f2c (f) (/ (* 5 (- f 32)) 9))
(defun temperature-conversion (spec)
(ecase (second spec)
(C (c2f (first spec)))
(F (f2c (first spec)))))
(temperature-conversion '(32 f))
==> 0
(temperature-conversion '(100 c))
==> 212
(temperature-conversion '(100))
*** - The value of (SECOND SPEC) must be one of C, F
The value is: NIL
The following restarts are available:
ABORT :R1 Abort main loop
I think this example is generally used to demonstrate how functions are first-class values.
With a little modification to sds's answer, you can have an ECASE statement that selects the appropriate function, which is then used by a surrounding FUNCALL.
(defun temperature-conversion (spec)
(destructuring-bind (temperature unit) spec
(funcall
(ecase unit (C #'c2f) (F #'f2c))
temperature)))
I added a DESTRUCTURING-BIND in case you don't know yet what it is.
I have a list of lists: (setq xs (list (list 1 2 3) (list 4 5 6) (list 7 8 9))). I want to remove a first element from each list to get ((2 3) (5 6) (8 9)). It's easy to do it non-destructively: (mapcar 'cdr xs). But I want mutate the original list. I tried:
(mapcar (lambda (x) (setf x (cdr x))) xs)
(mapcar (lambda (x) (pop x)) xs)
But it doesn't work. How to change each list of xs variable in-place, without creating any temporary lists, as efficiently as possible?
Use MAP-INTO:
CL-USER 16 > (let ((s (list (list 1 2 3)
(list 4 5 6)
(list 7 8 9))))
(map-into s #'rest s))
((2 3) (5 6) (8 9))
#Rainer Joswig's answer is correct, use map-into. The link gives example implementation using loop macro. If you want to implement map-into from scratch, or you use Emacs Lisp, you can also do it using dotimes. In Emacs Lisp dotimes is implemented in subr.el and doesn't require CL package. This is map-into with 1 sequence to map into the result sequence:
(defun map-into (r f xs)
(dotimes (i (min (length r) (length xs)) r)
(setf (elt r i)
(funcall f (elt xs i)))))
For version with variable amount of sequences we must sprinkle our code with apply and mapcar:
(defun map-into (r f &rest xss)
(dotimes (i (apply 'min (length r) (mapcar 'length xss)) r)
(setf (elt r i)
(apply f (mapcar (lambda (s) (elt s i))
xss)))))
We see, however, that elt inside dotimes makes our algorithm work in O(n2). We can optimize it to work in O(n) by using mapl (thanks #Joshua Taylor).
(defun map-into (rs f xs)
(mapl (lambda (r x) (setf (car r) (funcall f (car x)))) rs xs))
(defun map-into (rs f &rest xss)
(mapl (lambda (r xs)
(setf (car r)
(apply f (car xs))))
rs
(apply 'mapcar 'list xss))) ;; transpose a list of lists
The reason setf doesn't work inside mapcar is that setf is a complex macro that expands into expression that can manipulate the data it mutates. In a lambda scope inside mapcar it has access only to a variable, local to this lambda, not to the sequence passed to mapcar itself, so how should it know, where to put a modified value back? That's why mapcar code in the question returns modified list of lists but doesn't mutate it in-place. Just try (macroexpand '(setf (elt xs 0) (funcall 'cdr (elt xs 0)))) and see for yourself.