Trying to make a function that produces a n by n board
(new-board 2)
is supposed to produce
(list (make-posn 0 0) (make-posn 0 1) (make-posn 1 0) (make-posn 1 1))
The current rendition of my code is as follows:
(define (new-board y)
(build-list y (lambda (x) (build-list x (make-posn y x))))
)
I was pretty certain that it would work, but given my current knowledge and experience in Racket, I couldn't find the error.
I typed in:
> (new-board 3)
and got the error:
build-list: expects a procedure (arity 1); given (make-posn 3 0)
Am I committing a heinous crime by invoking build list inside of a build-list?
Please let me know. Thanks!
About this procedure:
(define (new-board y)
(build-list y (lambda (x) (build-list x
(make-posn y x))))) ;error!
Let's see what build-list receives as parameters. The first parameter is y, a number and the second parameter is a procedure, but you're passing the result of evaluating make-posn, which is not a procedure, it's a value. And that's the reason for the error you're getting.
EDIT 1 :
Now I understand what you intended. I can think of a solution, but it's a bit more elaborated than what you had in mind:
(define (new-board n)
(flatten
(map (lambda (x)
(map (lambda (y)
(make-posn x y))
(build-list n identity)))
(build-list n identity))))
(define (flatten lst)
(if (not (list? lst))
(list lst)
(apply append (map flatten lst))))
Here's how it works:
build-list is just being used for generating numbers from 0 to n-1, and I'm passing identity as the procedure, because no further processing is required for each number
For each number in the list, we also want to generate another list, again from 0 to n-1 because all the coordinates in the board are required. For example if n is 3 the coordinates are '((0 0) (0 1) (0 2) (1 0) (1 1) (1 2) (2 0) (2 1) (2 2))
I'm using a map inside a map for building the nested lists, a technique borrowed from here (see: "nested mappings")
Finally, I had to flatten the generated lists, and that's what flatten does (otherwise, we'd have ended with a list of lists of lists)
EDIT 2 :
Come to think of it, I found an even simpler way, closer to what you had in mind. Notice that the flatten procedure is unavoidable:
(define (new-board n)
(flatten
(build-list n
(lambda (x)
(build-list n
(lambda (y)
(make-posn x y)))))))
Now, when you type this:
(new-board 2)
The result is as expected:
(#(struct:posn 0 0) #(struct:posn 0 1) #(struct:posn 1 0) #(struct:posn 1 1))
If you look up the signature (contract) of build-list1, you see that it is
build-list : Nat (Nat -> X) -> (listof X)
So it takes a (natural) number, and then a function that expects a natural number and gives back an element of the type (X) that you want included in the list. So in your case, what specific type do you want X to be for each call you're making to build-list (it can be different in each case). In the case of the inner build-list, it looks like you're trying to make a list of posns. However, (make-posn y x) immediately makes a single posn and is not a function as build-list expects. So just as you provide a function (lambda (x) ...) to the outer build-list, you should also provide a function (lambda (...) ...) to the inner function.
Choosing the name x for the parameter of the first lambda might be a little confusing. What I might do is change the name of the new-board function's parameter to N, in that it seems like you want to create a board of N rows (and columns). And the purpose of the first build-list is to create each of those rows (or columns, depending how you want to think of it). So if you had:
(define (new-board N)
(build-list N (lambda (x) ...)))
And then you use it like:
(new-board 5)
it will reduce/simplify/evaluate as follows:
==> (build-list 5 (lambda (x) ...))
==> (list ( (lambda (x) (build-list ... x ...)) 0 )
( (lambda (x) (build-list ... x ...)) 1 )
( (lambda (x) (build-list ... x ...)) 2 )
( (lambda (x) (build-list ... x ...)) 3 )
( (lambda (x) (build-list ... x ...)) 4 )
==> (list (build-list ... 0 ...)
(build-list ... 1 ...)
(build-list ... 2 ...)
(build-list ... 3 ...)
(build-list ... 4 ...))
So, there's nothing wrong with nesting build-list. See if you can figure out now how to have the inner build-list work on producing a list of posns once the current row is fixed to a particular x value.
By the way, if you're allowed to use full Racket, there's a nice way to express the computation with for loops:
(define (new-board n)
(for*/list ([i n]
[j n])
(make-posn i j)))
Another way to get the same result but with a different approach is to use an arithmetic trick with quotient and remainder.
(define (new-board n)
(build-list (* n n)
(lambda (k)
(make-posn (quotient k n)
(remainder k n)))))
Related
Im trying to learn scheme and Im having trouble with the arithmetic in the Scheme syntax.
Would anyone be able to write out a function in Scheme that represents the Geometric Series?
You have expt, which is Scheme power procedure. (expt 2 8) ; ==> 256 and you have * that does multiplication. eg. (* 2 3) ; ==> 6. From that you should be able to make a procedure that takes a n and produce the nth number in a specific geometric series.
You can also produce a list with the n first if you instead of using expt just muliply in a named let, basically doing the expt one step at a time and accumulate the values in a list. Here is an example of a procedure that makes a list of numbers:
(define (range from to)
(let loop ((n to) (acc '())
(if (< n from)
acc
(loop (- 1 n) (cons n acc)))))
(range 3 10) ; ==> (3 4 5 6 7 8 9 10)
Notice I'm doing them in reverse. If I cannot do it in reverse I would in the base case do (reverse acc) to get the right order as lists are always made from end to beginning. Good luck with your series.
range behaves exactly like Python's range.
(define (range from (below '()) (step 1) (acc '()))
(cond ((null? below) (range 0 from step))
((> (+ from step) below) (reverse acc))
(else (range (+ from step) below step (cons from acc)))))
Python's range can take only one argument (the upper limit).
If you take from and below as required arguments, the definition is shorter:
(define (range from below (step 1) (acc '()))
(cond ((> (+ from step) below) (reverse acc))
(else (range (+ from step) below step (cons from acc)))))
Here is an answer, in Racket, that you probably cannot submit as homework.
(define/contract (geometric-series x n)
;; Return a list of x^k for k from 0 to n (inclusive).
;; This will be questionable if x is not exact.
(-> number? natural-number/c (listof number?))
(let gsl ((m n)
(c (expt x n))
(a '()))
(if (zero? m)
(cons 1 a)
(gsl (- m 1)
(/ c x)
(cons c a)))))
I want to solve the scheme problem
I define the code two, three, sq, plus
two is f(f(x)) // three is f(f(f(x)))
sq is square function ex ((two sq)3) is 81
plus is
(define (plus m n)
(lambda (f) (lambda (x) (m f (n f x))
I don't know why wrong that please let me know
You are confusing arity of functions. three and two are not functions of two parameters. They are functions that take a parameter and return a function. That returned function again takes a parameter.
Try the evaluating the following:
(let ((inc (lambda (x) (+ x 1))))
(list ((three inc) 0)
((two inc) 0)))
Your plus should be:
(define (plus m n)
(lambda (f) (lambda (x) ((m f) ((n f) x)))))
Now this should give you (3 2 5)
(let ((inc (lambda (x) (+ x 1))))
(list ((three inc) 0)
((two inc) 0)
(((plus two three) inc) 0)))
I'm currently preparing for an exam and thought that writing foldl with foldr would be a nice question to get tested on.
Anyways, I know that (foldl f base lst) returns (f xn (f x(n-1) . . . (f x1 base)
with the lst being (x1 . . . xn)
So what I currently have is this:
(define (foldl/w/foldr f base lst)
(foldr (lambda (x y) (f y (f x base))) base lst)))
This doesn't quite work, and I am unsure on how to proceed.
Using Haskell's documentation as a starting point (as mentioned by #soegaard in the comments), here's a working solution for this problem, using Racket syntax:
(define (foldl/w/foldr f base lst)
((foldr (λ (ele acc) (λ (x) (acc (f ele x))))
identity
lst)
base))
For example:
(foldl/w/foldr cons '() '(1 2 3 4 5))
=> '(5 4 3 2 1)
(foldl/w/foldr + 0 '(1 2 3 4 5))
=> 15
The key to understand this is that we're accumulating lambdas with delayed computations, not values, and at the end we invoke all the chain of lambdas passing the base value to start the computation. Also notice that the identity procedure is used as the first accumulator, and we accumulate more lambdas on top of it. For instance, this call:
(foldl/w/foldr + 0 '(1 2))
Will be evaluated as follows:
((lambda (x) ; this lambda is the value returned by foldr
((lambda (x)
(identity (+ 1 x))) ; add first element in the list (this gets executed last)
(+ 2 x))) ; add second element in the list (this gets executed first)
0) ; at the end, we invoke the chain of lambdas starting with the base value
=> 3
I am not a Lisp programmer, so this maybe not syntactically perfect, but it will be something like
foldl f a l = (foldr (lambda (h p) (lambda (x) (p (f x h))) )
l
(lambda (x) (x))
a))
The trick is to accumulate function instead of result value. I am applying four arguments to foldr, because in this case regular foldr returns function, that will take "a" as an argument.
This the task:
Write a function (random-number-list n lim) which returns a list of n random integers in the range 0 through lim-1
This is my Code: (I am using #lang EOPL in DrRacket)
(define (random-number-list n lim)
(letrec ((maker
(lambda (n lim result)
(let loop ((g lim) (result '()))
(if (= g 0)
result
(loop (- lim 1) (cons (random lim) result)))))))
(maker n lim '())))
This should be what it produce:
(random-number-list 10 20) => (1 11 4 18 3 12 17 17 8 4)
When I run the code I receive an error dealing with "(random lim)." Something to with random. Would anyone know the reason? Also, am I on the correct track?
The main problem with your code is in this line:
(loop (- lim 1) (cons (random lim) result))
You're decrementing lim but testing against g, which remains unchanged, leading to an infinite loop. Also, g was incorrectly initialized in this line:
((g lim) (result '()))
This should fix the problems:
(define (random-number-list n lim)
(letrec ((maker
(lambda (n lim result)
(let loop ((g n) (result '()))
(if (= g 0)
result
(loop (- g 1) (cons (random lim) result)))))))
(maker n lim '())))
Given that you're using Racket, know that a simpler solution is possible:
(define (random-number-list n lim)
(build-list n (lambda (x) (random lim))))
Either way, it works as expected:
(random-number-list 10 20)
=> '(13 7 5 9 3 12 7 8 0 4)
The main reason you get an error is that the langiage #!eopl doesn have a procedure named random. If you se the eported symbols of eopl it simply doesn't exist. It does exist in #!racket though.
As Oscar pointed out there were some logical errors that leads to infinite loops. An honest mistake, but I also notice you use g instead of n in your inner loop. It's very common to use the original name instead of the chosen local variable so a common way to not do that mistake is to shadow the original variable.
There is also only need for one local procedure. Here are my corrections with either keeping the named let or the letrec:
#!racket
;; with letrec
(define (random-number-list n lim)
(letrec ((maker
(lambda (n result)
(if (zero? n)
result
(maker (- n 1)
(cons (random lim) result))))))
(maker n '())))
;; with named let
(define (random-number-list2 n lim)
(let maker ((n n) (result '()))
(if (zero? n)
result
(maker (- n 1)
(cons (random lim) result)))))
I left lim out since it never changes and i used the same name maker to illustrate it's exactly the same that happens in these two, only the syntax are different. Many implementations actually rewrites the named let to something very similar to the letrec version.
An alternative:
(define (random-number-list n lim)
(build-list n (λ (x) (random lim)))
Here build-list builds a list of n elements.
Each element is the result of calling (λ (x) (random lim))
which ignores x and returns a random number between 0 and lim-1.
I'm running a for loop in racket, for each object in my list, I want to execute two things: if the item satisfies the condition, (1) append it to my new list and (2) then print the list. But I'm not sure how to do this in Racket.
This is my divisor function: in the if statement, I check if the number in the range can divide N. If so, I append the item into my new list L. After all the loops are done, I print L. But for some unknown reason, the function returns L still as an empty list, so I would like to see what the for loop does in each loop. But obviously racket doesn't seem to take two actions in one "for loop". So How should I do this?
(define (divisor N)
(define L '())
(for ([i (in-range 1 N)])
(if (equal? (modulo N i) 0)
(append L (list i))
L)
)
write L)
Thanks a lot in advance!
Note: This answer builds on the answer from #uselpa, which I upvoted.
The for forms have an optional #:when clause. Using for/fold:
#lang racket
(define (divisors N)
(reverse (for/fold ([xs '()])
([n (in-range 1 N)]
#:when (zero? (modulo N n)))
(displayln n)
(cons n xs))))
(require rackunit)
(check-equal? (divisors 100)
'(1 2 4 5 10 20 25 50))
I realize your core question was about how to display each intermediate list. However, if you didn't need to do that, it would be even simpler to use for/list:
(define (divisors N)
(for/list ([n (in-range 1 N)]
#:when (zero? (modulo N n)))
n))
In other words a traditional Scheme (filter __ (map __)) or filter-map can also be expressed in Racket as for/list using a #:when clause.
There are many ways to express this. I think what all our answers have in common is that you probably want to avoid using for and set! to build the result list. Doing so isn't idiomatic Scheme or Racket.
It's possible to create the list as you intend, as long as you set! the value returned by append (remember: append does not modify the list in-place, it creates a new list that must be stored somewhere) and actually call write at the end:
(define (divisor N)
(define L '())
(for ([i (in-range 1 N)]) ; generate a stream in the range 1..N
(when (zero? (modulo N i)) ; use `when` if there's no `else` part, and `zero?`
; instead of `(equal? x 0)`
(set! L (append L (list i))) ; `set!` for updating the result
(write L) ; call `write` like this
(newline)))) ; insert new line
… But that's not the idiomatic way to do things in Scheme in general and Racket in particular:
We avoid mutation operations like set! as much as possible
It's a bad idea to write inside a loop, you'll get a lot of text printed in the console
It's not recommended to append elements at the end of a list, that'll take quadratic time. We prefer to use cons to add new elements at the head of a list, and if necessary reverse the list at the end
With all of the above considerations in place, this is how we'd implement a more idiomatic solution in Racket - using stream-filter, without printing and without using for loops:
(define (divisor N)
(stream->list ; convert stream into a list
(stream-filter ; filter values
(lambda (i) (zero? (modulo N i))) ; that meet a given condition
(in-range 1 N)))) ; generate a stream in the range 1..N
Yet another option (similar to #uselpa's answer), this time using for/fold for iteration and for accumulating the value - again, without printing:
(define (divisor N)
(reverse ; reverse the result at the end
(for/fold ([acc '()]) ; `for/fold` to traverse input and build output in `acc`
([i (in-range 1 N)]) ; a stream in the range 1..N
(if (zero? (modulo N i)) ; if the condition holds
(cons i acc) ; add element at the head of accumulator
acc)))) ; otherwise leave accumulator alone
Anyway, if printing all the steps in-between is necessary, this is one way to do it - but less efficient than the previous versions:
(define (divisor N)
(reverse
(for/fold ([acc '()])
([i (in-range 1 N)])
(if (zero? (modulo N i))
(let ([ans (cons i acc)])
; inefficient, but prints results in ascending order
; also, `(displayln x)` is shorter than `(write x) (newline)`
(displayln (reverse ans))
ans)
acc))))
#sepp2k has answered your question why your result is always null.
In Racket, a more idiomatic way would be to use for/fold:
(define (divisor N)
(for/fold ((res null)) ((i (in-range 1 N)))
(if (zero? (modulo N i))
(let ((newres (append res (list i))))
(displayln newres)
newres)
res)))
Testing:
> (divisor 100)
(1)
(1 2)
(1 2 4)
(1 2 4 5)
(1 2 4 5 10)
(1 2 4 5 10 20)
(1 2 4 5 10 20 25)
(1 2 4 5 10 20 25 50)
'(1 2 4 5 10 20 25 50)
Since append is not really performant, you usually use cons instead, and end up with a list you need to reverse:
(define (divisor N)
(reverse
(for/fold ((res null)) ((i (in-range 1 N)))
(if (zero? (modulo N i))
(let ((newres (cons i res)))
(displayln newres)
newres)
res))))
> (divisor 100)
(1)
(2 1)
(4 2 1)
(5 4 2 1)
(10 5 4 2 1)
(20 10 5 4 2 1)
(25 20 10 5 4 2 1)
(50 25 20 10 5 4 2 1)
'(1 2 4 5 10 20 25 50)
To do multiple things in a for-loop in Racket, you just write them after each other. So to display L after each iteration, you'd do this:
(define (divisor N)
(define L '())
(for ([i (in-range 1 N)])
(if (equal? (modulo N i) 0)
(append L (list i))
L)
(write L))
L)
Note that you need parentheses to call a function, so it's (write L) - not write L. I also replaced your write L outside of the for-loop with just L because you (presumably) want to return L from the function at the end - not print it (and since you didn't have parentheses around it, that's what it was doing anyway).
What this will show you is that the value of L is () all the time. The reason for that is that you never change L. What append does is to return a new list - it does not affect the value of any its arguments. So using it without using its return value does not do anything useful.
If you wanted to make your for-loop work, you'd need to use set! to actually change the value of L. However it would be much more idiomatic to avoid mutation and instead solve this using filter or recursion.
'Named let', a general method, can be used here:
(define (divisors N)
(let loop ((n 1) ; start with 1
(ol '())) ; initial outlist is empty;
(if (< n N)
(if(= 0 (modulo N n))
(loop (add1 n) (cons n ol)) ; add n to list
(loop (add1 n) ol) ; next loop without adding n
)
(reverse ol))))
Reverse before output since items have been added to the head of list (with cons).