Im learning Racket and have some troubles.
I want to iterate over a list and find the index of some value. I have the following code:
(define (index list entry)
(define index 0)
(for ([i list])
#:break (equal? i entry)
(+ index 1))
index)
But the function always returns 0. Can anyone point out my mistake?
I know that there are functions for that, but I want to learn the syntax.
First of, the easiest way to get the index of an element in a list is index-of:
> (index-of '(1 3 5 2 4) 5)
2
Another way I will sometimes do it is using the in-naturals sequence. So taking your code:
(define (index list entry)
(for/last ([i list]
[index (in-naturals)])
#:break (equal? i entry)
index))
This works because for loop constructs iterates as many times as the shortest sequence. in-naturals will go on forever, so it will count only as many elements are in list, and still break when your #:break clause is met.
A third option is to use for/fold, again based on your code:
(define (index list entry)
(for/fold ([acc 0])
([i list])
#:break (equal? i entry)
(add1 acc)))
This works because acc acts as an accumulator, and gets incremented every iteration until your #:break clause is met.
Finally, your original code has two primary problems.
First, the for form always returns (void). You need to use for/last if you want it to return the last element.
Second, the + function only adds two numbers. It does not store the result back into the variable. So if you really want to use mutation here, you would need to do:
(define (index list entry)
(define index 0)
(for ([i list])
#:break (equal? i entry)
(set! index (+ index 1)))
index)
But again, I highly recommend just using index-of, since its already in the standard library.
Related
I am new to Racket and functional languages in general. For now I am just trying to prepend items to a list. The concepts are a bit confusing and not sure why my code isn't working.
I am trying to do dot product calculations.
I have a function called "dProduct" that takes 2 lists (A and B) and multiplies each corresponding element in them.
;function takes dot product
(define (dProduct A B)
(define C '()) ; define list to store the multiplied elements
;multiply ea lists elements
(for ([i A] [j B])
(display (* i j)) ;THIS WORKS
(cons (* i j) C) ;APPARENTLY DOESN'T WORK
)
;THIS FOR LOOP DISPLAYS NOTHING
;display the new list "C"
(for ([k C])
(display k)
)
)
I don't understand why I can't use cons to prepend the new multiplied elements to my new list "C". What am I missing? Everything compiles fine. Would like to figure this out so I can finish this function :) Any help would be great. Thanks!
Lists are immutable, and cons does not prepend an element to an existing list. Instead, it produces a new list with the element prepended:
> (define x '(2 3))
> (cons 1 x)
'(1 2 3)
> x
'(2 3)
Since your question is tagged functional-programming, I will assume that you probably want to know how to do this functionally, and functional programming generally discourages mutating values or bindings.
Instead of mutating a binding, you should build up a new structure functionally. The easiest way to do this is to change your use of for to for/list, which produces a list of return values:
(define C
(for/list ([i A] [j B])
(* i j)))
For this program, you could make it even simpler by using the higher-order function map, which acts like a “zip” when provided more than one list argument:
(define C (map * A B))
Since for always returns #<void>, it’s only useful for producing side-effects, and in functional programming, you generally try and keep side-effects to a minimum. For that reason, you will likely find that for/list and for/fold are actually much more commonly useful in idiomatic Racket than plain for is.
Current C list has to be given new value of (cons (* i j) C) and this can be done using set! :
(define (dProduct A B)
(define C '())
(for ([i A] [j B])
(displayln (* i j))
(set! C (cons (* i j) C))) ; NOTE set! HERE.
(for ([k C])
(displayln k)))
Note that the use of set! is strongly discouraged and for/list is much better way to achieve desired result here.
I'm having trouble incorporating a recursive function that squares a number.
Basically I am trying to write a function that keeps calling the Add function x number of times to square it. So if it is 7 it should call it seven times to get 49.
(define (Add a b)
(if (and (number? a) (number? b))
(+ a b)
(lambda (x)
(+ (a x) (b x)))))
(define i 0)
(define ans 0)
(define (Square a)
(when (> i a)
((Add a ans) (+ i 1 ))))
The main issue I'm running into is that the square function only goes through the loop once, I'm not sure why the condition won't update/keep going through the loop till it reaches that condition.
Writing square directly is a big pain. It's much easier to write a recursive multiply function and then just have your square function call multiply. Follow the design recipe for recursion on the natural numbers, as it appears in section 9.3 of HtDP.
By the way, if you haven't already written a bunch of recursive functions on more standard self-referential data definitions (e.g. lists), then, well, I claim that your instructor is doing in wrong.
You should make everything that changes parameters. Imagine you want to make the factorial then two values change. It's the result and the iteration of the number down to zero.
(define (factorial value)
(define (helper cur ans)
(if (zero? cur)
ans ; finished. return the answer
(helper (- cur 1) ; recur by updating n
(* cur ans)))) ; and update the answer
(helper value 1))
Again. It's exactly the same as my example in the comment except it does something else at each step. The basic building blocks are the same and something that would square the argument is very similar.
I'm trying to write a function that adds an element to each element of a given powerset. No matter what it always evaluates (null pset) as true. I can't understand why.
Here's what I have so far:
(defun addxtopowerset(x pset)
(cond
((null pset) (list x '())) ; If the powerset is null, display x and NIL.
;;First display a list combining x and the first item of pset. Then display the first item of pset itself. Then recursively call the function passing the rest of pset as a parameter.
(T (list 'x (car pset))(list (car pset))
(addxtopowersetch x (cdr pset)))))
First, note that in the terminal case you should return an empty list, since is in the recursion that all the elements of the powerset are processed, and we should assume that a powerset is always a list of list, each of them representing a set (in fact, the powerset of an empty set contains at least one element, the empty set itself).
So, since a powerset is a non-empty list, the task of adding a new element to the powerset can be solved by adding to the result, for each list of the powerset, both the list and a copy of the list with the element added.
In both cases, “add” means: get something and return a new-something, and use the value returned, otherwise, as Rainer Joswig note, “the result go straight into the digital nirvana”. In other words, in the recursive case your function must add the two values, the list and the new list with the element added, to the result of the recursive call. So, here is the function:
(defun addxtopowerset(x pset)
(if (null pset)
nil
(append (list (car pset) (cons x (car pset)))
(addxtopowerset x (cdr pset)))))
Finally, here a couple of alternative ways of defining the function, the first one with the high order function mapcan:
(defun addxtopowerset(x pset)
(mapcan (lambda(y) (list y (cons x y))) pset))
and the second one with a loop:
(defun addxtopowerset(x pset)
(loop for y in pset append (list y (cons x y))))
So I am very new to lisp, and not that advanced of a programmer yet. Just getting started really.
I'm messing around trying to get a very simple genetic algorithm going from scratch, and while most of my code seems to execute as desired, I'm stuck with such a simple bug/misunderstanding that I am blocked from the bottom... There is clearly something I am not getting despite my hours online trying to find a solution..
Basically, I know it has something to do with the fact I am trying to call a variable as if it were an operator (which the variable holds) and thus it tells me my function (which is really just a variable holding an operator) is not defined.
The start of my code works fine.
(defvar *nb* 8)
(defvar *random-operators* '(+ - * /))
(defun get-operator ()
"Returns an element of the list of operators chosen at random."
(nth (random (length *random-operators*)) *random-operators*))
So (get-operator) does get me one of the four random operators, as desired.
I used this even simpler code to test the structure of my code, and it works as desired.
(defun ga-simple ()
"Returns the value of genome once it matches *nb* and prints
the number of generations required."
(do ((genome (random 10) (random 10))
(generation-counter 1 (incf generation-counter)))
((eql genome *nb*)
(format t
"The solution is ~S, and it took ~D generations"
genome
generation-counter))))
The problem comes when I try and create a genome composed of three variables, one holding the operator, and the other two, the integers.
(defun ga-with-operator ()
(do ((genome 42 (opr1 int1 int2))
(generation-counter 0 (incf generation-counter))
(opr1 + (get-operator)
(int1 (random 10) (random 10))
(int2 (random 10) (random 10))
((eql genome *nb*)
(format t
"The solution is ~S, and it took ~D generations"
genome
generation-counter))))
my compiler warnings tell me where the problem is...
;Compiler warnings for "./ga-one.lisp" :
; In GA-WITH-OPERATOR: Unused lexical variable OPR1
;Compiler warnings for "./ga-one.lisp" :
; In GA-WITH-OPERATOR: Undefined function OPR1/
And so clearly a call to the function (ga-with-operator) says opr1 is an undefined-function-call. So from what I gather when the "do" macro checks the increment condition for the variable genome, it reads the list, expecting opr1 to be an operator and not a variable holding an operator... Now, an operator simply entered works perfect here, but I don't know how to make lisp use the evaluated value of opr1, which is an operator, as the operator for the integers...
To simplify, I made a function trying to construct a single genome using my get-operator function, and failed hard even there lol
(defun get-genome ()
(let ((operator1 (get-operator)))
(operator1 (random 10) (random 10))))
So I made a test-let function to make sure my "let" variable assignment is right...
(defun test-let ()
(let ((rand (get-operator)))
(print rand)))
Which it does... So now I am getting desperate and missing something obviously very simple and yet crucial to make it all stick together.
If someone could explain to me, or just show me, how to get the simple (get-genome) function to work I would really appreciate it. I know lisp expects an operator as the first element in the list, and my error stems from me feeding it a variable holding an operator instead... How do I convince it my variable is the operator it is holding?
in case anyone wants to know the working code...
(defvar *nb* 42)
(defvar *random-operators* '(+ - * /))
(defun get-operator ()
"Return an element of the list of operators chosen at random."
(nth (random (length *random-operators*)) *random-operators*))
(defun get-genome ()
(let ((operator1 (get-operator)))
(funcall operator1 (+ 1 (random 9)) (+ 1 (random 9)))))
(defun ga-with-operator ()
(do ((genome (get-genome) (get-genome))
(generation-counter 0 (1+ generation-counter)))
((eql genome *nb*)
(format t "The solution is ~S, and it took ~D generations"
genome generation-counter))))
In Common Lisp you need to use FUNCALL if the function is returned by a function or if the function is stored in a variable.
(defun get-genome ()
(let ((operator1 (get-operator)))
(funcall operator1 (random 10) (random 10))))
Common Lisp has different namespaces for functions and for values. Thus a name can both be a variable and a function:
(defun foo (list)
(list list list))
The first list in the last line calls the global function called list and the second and third are actually the local variable list.
(defun ga-with-operator ()
(do ((genome 42 (opr1 int1 int2))
(generation-counter 0 (incf generation-counter))
(opr1 + (get-operator)
(int1 (random 10) (random 10))
(int2 (random 10) (random 10))
((eql genome *nb*)
(format t
"The solution is ~S, and it took ~D generations"
genome
generation-counter))))
Above function has more problems.
Can you see the first? Hint: try indenting it correctly. Are the parentheses correct?
also: + is not a function. It is a variable in your code. To make it a function you would need to quote or function quote it. '+ or #'+.
you also don't need to INCF the generation-counter. Just adding 1 is fine. The DO loop updates the variable. Use (1+ generation-counter).
Of course, FUNCALL / APPLY is what you want, but just to complete the picture, note that this also works:
(setf (symbol-function 'operator1) (get-operator))
(operator1 (+ 1 (random 9)) (+ 1 (random 9)))
The reason you generally don't want to do this is that binding of the symbol-function slot is global.
My professor has given us a refresher assignment in clisp. One exercise is to achieve the same thing in three ways: Return a flattened list of all positive integers in a given list.
Now, there's only one way I really like doing this, using cons and recursion, but he wants me to do this using mapcan and a loop (I suspect lisp is not his first choice of language because this style of coding feels extremely resistant to the nature of lisp). I'm having a hard time working out how one would do this using a loop...I need to first start a list, I suppose?
I apologize for vague language as I'm not really sure how to TALK about using a functional language to write procedurally. Following is my first attempt.
(defun posint-loop (l)
(loop for i in l
do (if (listp i)
(posint-loop i)
(if (integerp i)
(if (> i 0)
(append i) ; this doesn't work because there's nothing to
; start appending to!
nil)
nil))))
In order to establish a new lexical binding, use let or the with keyword of loop. In order to extend an existing list, you might want to use push; if you need the original order, you can nreverse the new list finally.
Another way would be to use the when and collect keywords of loop.
Another hint: mapcan implicitly creates a new list.
Mapcan applies a function to each element of a list, expecting the function to return a list, and then concatenates those resulting lists together. To apply it to this problem, you just need to process each element of the toplevel list. If the element is a list, then you need to process it recursively. If it's not, then you either need to return an empty list (which will add no elements to the final result) or a list of just that element (which will add just that element to the final result):
(defun flatten2 (list)
(mapcan (lambda (x)
(cond
((listp x) (flatten2 x))
((and (integerp x) (plusp x)) (list x))
(t '())))
list))
(flatten2 '((a 1 -4) (3 5 c) 42 0))
;=> (1 3 5 42)
With loop, you can do just about the same thing with the recognition that (mapcan f list) is functionally equivalent to (loop for x in list nconc (funcall f x)). With that in mind, we have:
(defun flatten3 (list)
(loop for x in list
nconc (cond
((listp x) (flatten3 x))
((and (integerp x) (plusp x)) (list x))
(t '()))))