Using struct in Racket - scheme

I am a newbie in Racket. I was trying question 1 from here. Following is the code that I could make :
#lang racket
(require 2htdp/image)
(require rackunit)
(require rackunit/text-ui)
(require "extras.rkt")
(define curr-dir "n")
(define curr-x 30)
(define curr-y 40)
;; Structure that I thought about
(define-struct robot (x y direction))
(define irobot (make-robot curr-x curr-y curr-dir))
(define MAX_HEIGHT 200)
(define MAX_WIDTH 400)
(define (render-robot)
(place-image
(crop 14 0 10 20 (circle 10 "solid" "blue"))
19 10
(circle 10 "solid" "red"))
)
(define (spawn-robot x y direction)
(place-image
(cond
[(string=? "n" direction) (rotate 90 (render-robot))]
[(string=? "e" direction) (render-robot)]
[(string=? "w" direction) (rotate 180 (render-robot))]
[(string=? "s" direction) (rotate 270 (render-robot))]
)
x y
(empty-scene MAX_WIDTH MAX_HEIGHT)
)
)
(define (initial-robot x y)
(if (and (<= x (- MAX_HEIGHT 10)) (<= y (- MAX_WIDTH 10)))
(spawn-robot x y curr-dir)
(error "The placement of the robot is wrong!")
)
)
(define robot1 (initial-robot curr-x curr-y))
;;-----------------------------------------------------;;
;; Doubt Here (Make the robot turn left)
(define (robot-left robot-obj)
(set! curr-dir "w") ;; Hard coded for north direction
(initial-robot curr-x curr-y)
)
;; Doubt Here (Function checks whether robot is facing north or not.)
(define (robot-north? robot-obj)
(if (string=? "n" curr-dir) (true) (false))
)
In the interpreter I tries this out:
I was thinking that the code is probably going fine but still some doubts cropped up in my mind:
In the code according to me using a Structure (make-struct) should
have been good but according to explanation of the question I think
the instance of robot is the result of the function initial-robot.
Is using a Structure feasible?
In the functions robot-left and robot-north? how should I use
robot1 as the argument? Setting a global variable that stores the
current direction of the object can to used for the functions
mentioned. What should I do here?
Any suggestion is welcome.
Thanks!

You are correct that a struct would be a better choice:
1) You wouldn't be limited to a single robot in your code, and
2) You would be programming in a functional manner, which is what the assignment wants.
So, with your robot struct:
(define-struct robot (x y direction))
Make sure you give a proper data definition to the struct.
;; A Robot is a (make-robot x y direction), where:
;; - x is an integer
;; - y is an integer
;; - direction is a string
Although, I'd recommend using symbols instead of strings for direction.
(robot-left):
;; Turns a robot to the left.
;; Robot -> Robot
(define (robot-left robot-obj)
(make-robot (robot-x robot-obj)
(robot-y robot-obj)
"w"))
(robot-north?):
;; Does robot-obj face north?
;; Robot -> Boolean
(define (robot-north? robot-obj)
(string=? (robot-direction robot-obj) "n"))
Now, to incorporate these functions into your code, you need to make sure that you separate the idea of data and output images, which you currently don't.
(initial-robot) should not render at all. It should just return an instance of a Robot, as defined in our data definition.
Notice that the spec given in this homework assignment does not require you to render at all. This would be a separate undertaking. All functions that they ask you to define strictly deal with data. Afterwards, you can consider rendering to test your functions visually, as an extra to the unit tests you should also create for each function.
The code that I've provided you should be a good starting point for figuring out how you would design the rest of your functions. Don't worry about rendering until the end! Don't forget that every signature given in the homework assignment that mentions Robot is referencing the data definition that we have created for our robot struct.

Related

Difference between usage of set! and define

In the following code:
(define x 14)
(display x) ; x = 14
(set! x 13)
(display x) ; x = 13
(define x 14)
(display x) ; x = 14
(set! y 13) ; SchemeError: y not found!
(display y)
What we a use case where someone would want to use set! over just define, if define can be used for everything that set! can be used for + the actual definition itself?
define creates a new binding between a name and a value (a variable), set! mutates an existing binding. These are not the same operation, languages like Python which confuse the operations notwithstanding.
In particular something like
(define x 1)
...
(define x 2)
is illegal: you can only create the variable once. Implementations may not check this, but that doesn't make it legal. Once you've created the binding, if you want to modify it you need to do that with set!.
A particular case where implementations (including Racket) are intentionally sloppy about this is when they are being used interactively. Quite often if you're interacting with the system you may want to say, for instance:
> (define square (λ (x) (+ x x)))
... ooops, that's not right, is it?
... Better fix it using the command-line editing
> (define square (λ (x) (* x x)))
In cases like that it's clearly better for the implementation just to allow this repeated definition of things, because it's going to make the life of users enormously easier.
But in programs such repeated definitions in the same scope are (almost?) always bugs, and they really ought to be caught: if you want to mutate a binding, use set!. Racket in particular will certainly puke on these.
Finally note that define is simply not legal in all the places set! is: even in Racket (which allows define in many more places than Scheme does) this is not even slightly legal code:
(define (foo x)
(define v x)
(if (odd? x)
(define v (* v 2))
(define v (/ v 2)))
v)
While this is
(define (foo x)
(define v x)
(if (odd? x)
(set! v (* v 2))
(set! v (/ v 2)))
v)
(It's still terrible code, but it is legal.).

How to calculate the degree of a polynomial in scheme?

I need to create a scheme code that allows me to calculate the degree of a polynomial and show it, is there a special function in scheme that allows me to treat them?
pd: What is the way to raise these types of problems?
There is no such function just like there are no functions for guns in games in the standard libraries. There isn't even one data structure for a polynomial.
As with all user defined extensions you have the power to model your data as you wish and you make an interface to work with that data. This is how you extend the language to support the data you want to play with.
;; this is not part of the interface
(define tag-point (list 'point))
;; these are the interface
(define (point x y)
(list tag-point x y))
(define point-x cadr)
(define point-y caddr)
(define (point? p)
(and (pair? p)
(eq? (car p) tag-point)))
;; implemented distance that uses the interface
(define (distance p1 p2)
;; (assert (and (point? p1) (point? p2)))
(sqrt (+ (square (- (point-x p1) (point-x p2)))
(square (- (point-y p1) (point-y p2))))))
(distance (point 3 0 ) (point 0 4)) ; ==> 5
Now you can change your data structure as long as the interface stays intact:
;; implement points using complex numbers
(define (point x y) (make-rectangular x y))
(define (point-x p) (real-part p))
(define (point-y p) (imag-part p))
(define (point? p) (complex? p))
One could just do (define point make-rectangular) but then the interface documentation would be vague.
In the SICP videos I remember they did a polynomial type. It's in part 4B. It explains pretty much the same as I do here and they actually implement polynomials as a type you can do arithmetic on. Thus it might not be what you are looking for, but their data structure can give you an idea.

Function Definitions After Expressions in Scheme

I understand I can't define a function inside an expression, but I'm getting errors defining one after an expression within the same nested function. I'm using R5RS with DrScheme.
For example, this throws an error, 'define: not allowed in an expression context':
(define (cube x)
(if (= x 0) 0) ;just for example, no reason to do this
(define (square x) (* x x))
(* x (square x)))
In R5RS you can only use define in rather specific places: in particular you can use it at the beginning (only) of forms which have a <body>. This is described in 5.2.2. That means in particular that internal defines can never occur after any other expression, even in a <body>.
Native Racket (or whatever the right name is for what you get with#lang racket) is much more flexible in this regard: what you are trying to do would (apart from the single-armed if) be legal in Racket.
You can use define inside another definition. Some Schemes won't allow you to have an if without the else part, though. This works for me:
(define (cube x)
(if (= x 0) 0 1) ; just for example, no reason to do this
(define (square x) (* x x))
(* x (square x)))
Have you tried making the definition at the beginning? maybe that could be a problem with your interpreter.
define inside a procedure body (that includes all forms that are syntactic sugar for procedures, like let, let*, and letrec) are only legal before other expressions and never after the first expression and it can not be the last form.
Your example shows no real reason for why you would want to have an expression before definitions. There is no way you can get anything more than moving all define up to the beginning. eg.
(define (cube x)
;; define moved to top
(define (square x) (* x x))
;; dead code moved under define and added missing alternative
(if (= x 0) 0 'undefined)
(* x (square x)))
If the code isn't dead. eg. it's the tail expression you can use let to make a new body:
(define (cube x)
(if (= x 0)
0
(let ()
;; this is top level in the let
(define (square x) (* x x))
;; required expression
(* x (square x)))))
I think perhaps we would need an example where you think it would be warranted to have the define after the expression and we'll be happy to show how to scheme it up.

Data enforcing in scheme

In my implementation below of vector and line segment, it seems weird the way that I'm using car and cdr in my implementation of seg-start and xcor. It seems too general, or is this the way loosely typed languages work? For example, I can't say get the xcor of just only a car of a vector.
(define make-vector cons) // accept 2 numbers and make a vector.
(define make-segment make-vector) // 2 vectors connected to make a segment.
(define seg-start car)
(define seg-end cdr)
(define xcor car)
(define ycor cdr)
(define vector1 (make-vector 1 2))
(define vector2 (make-vector 3 4))
(define seg1 (make-segment vector1 vector2))
(xcor (seg-start seg1))
(ycor (seg-start seg1))
If your Scheme implementation supports records (SRFI 9) or structs, it's often better to use that rather than just cons cells or vectors. (Though, records and structs usually use vectors behind the scenes, but that's an implementation detail.)
If make-vector is defined:
(define make-vector list)
and make-segment:
(define make-segment list) ; don't redirect through `make-vector`
Then the accessors can be
(define seg-start first)
(define seg-end second)
and
(define xcor first)
(define ycor second)
The advantage is that it becomes easy to extend the system and add a z coordinate or create a polygons or series of connected vectors without rewriting the code. Cons cells will reduce memory usage slightly, but if you're running out of RAM in an age of cheap gigabytes, it may be time to look at rewriting critical sections in C.
Using cons, car and cdr is not bad, but users of that interface might face weird errors when they try your interface on bad data. I usually start using simple objects this way and move on the second I need more. you can combine this with a tag to be able to make type checking. eg.
(define pair-tag (list 'pair))
(define (kons a d) (cons pair-tag (cons a d)))
(define (kons? x) (and (pair? x) (eq? (car x) pair-tag)))
(define (kar x) (if (kons? x) (cadr x) (error "not a kons")))
(define (kdr x) (if (kons? x) (cddr x) (error "not a kons")))
There are ways to make new types with SRFI-9 Record types. You'll typically get type checking and the error messages gets better without having to do it yourself.
For a full object system and OO programming you can go for TinyCLOS.
Depending on your implementation that code might need some tweaking but I did get it working on Racket R6RS once (I think it runs out of the box for Ikarus)

optimizing simple Common Lisp gibbs sampler program

As an exercise, I rewrote the example program in the blog post Gibbs sampler in various languages (revisited) by Darren Wilkinson.
The code appears below. This code runs on my (5 year old) machine in around 53 seconds, using SBCL 1.0.56, creating a core image using buildapp, and then running it with
time ./gibbs > gibbs.dat
Since this was how the timings were calculated for the other languages in the post, I thought I would do something comparable
The C code in the post runs in around 25 seconds. I'd like to try and speed up the Lisp code if possible.
##############################
gibbs.lisp
##############################
(eval-when (:compile-toplevel :load-toplevel :execute)
(require :cl-rmath) (setf *read-default-float-format* 'double-float))
(defun gibbs (N thin)
(declare (fixnum N thin))
(declare (optimize (speed 3) (safety 1)))
(let ((x 0.0) (y 0.0))
(declare (double-float x y))
(print "Iter x y")
(dotimes (i N)
(dotimes (j thin)
(declare (fixnum i j))
(setf x (cl-rmath::rgamma 3.0 (/ 1.0 (+ (* y y) 4))))
(setf y (cl-rmath::rnorm (/ 1.0 (+ x 1.0)) (/ 1.0 (sqrt (+ (* 2 x) 2))))))
(format t "~a ~a ~a~%" i x y))))
(defun main (argv)
(declare (ignore argv))
(gibbs 50000 1000))
Then I built the executable gibbs with calling sh gibbs.sh with gibbs.sh as
##################
gibbs.sh
##################
buildapp --output gibbs --asdf-tree /usr/share/common-lisp/source/ --asdf-tree /usr/local/share/common-lisp/source/ --load-system cl-rmath --load gibbs.lisp --entry main
I get 6 compiler notes when compiling with SBCL 1.0.56, which reproduce below. I'm not sure what to do about them, but would be grateful for any hints.
; compiling file "/home/faheem/lisp/gibbs.lisp" (written 30 MAY 2012 02:00:55 PM):
; file: /home/faheem/lisp/gibbs.lisp
; in: DEFUN GIBBS
; (SQRT (+ (* 2 X) 2))
;
; note: unable to
; optimize
; due to type uncertainty:
; The result is a (VALUES (OR (DOUBLE-FLOAT 0.0) (COMPLEX DOUBLE-FLOAT))
; &OPTIONAL), not a (VALUES FLOAT &REST T).
; (/ 1.0d0 (SQRT (+ (* 2 X) 2)))
;
; note: unable to
; optimize
; due to type uncertainty:
; The second argument is a (OR (DOUBLE-FLOAT 0.0)
; (COMPLEX DOUBLE-FLOAT)), not a (COMPLEX
; DOUBLE-FLOAT).
;
; note: forced to do static-fun Two-arg-/ (cost 53)
; unable to do inline float arithmetic (cost 12) because:
; The second argument is a (OR (DOUBLE-FLOAT 0.0) (COMPLEX DOUBLE-FLOAT)), not a DOUBLE-FLOAT.
; The result is a (VALUES (OR (COMPLEX DOUBLE-FLOAT) (DOUBLE-FLOAT 0.0))
; &OPTIONAL), not a (VALUES DOUBLE-FLOAT &REST T).
; (CL-RMATH:RGAMMA 3.0d0 (/ 1.0d0 (+ (* Y Y) 4)))
;
; note: doing float to pointer coercion (cost 13)
; (SQRT (+ (* 2 X) 2))
;
; note: doing float to pointer coercion (cost 13)
; (CL-RMATH:RNORM (/ 1.0d0 (+ X 1.0d0)) (/ 1.0d0 (SQRT (+ (* 2 X) 2))))
;
; note: doing float to pointer coercion (cost 13)
;
; compilation unit finished
; printed 6 notes
; /home/faheem/lisp/gibbs.fasl written
; compilation finished in 0:00:00.073
UPDATE 1: Rainer Joswig's answer pointed out that the argument of the SQRT might be negative, which
was the source of the obscure compiler notes I was seeing, namely
The result is a (VALUES (OR (DOUBLE-FLOAT 0.0) (COMPLEX DOUBLE-FLOAT))
; &OPTIONAL), not a (VALUES FLOAT &REST T).
The compiler was complaining that since it didn't know whether the value of the argument was positive,
the result could be a complex number. Since in the example, the value x is a sample variate from the gamma distribution,
it is always greater than 0. It was helpfully pointed out by Stephan in the SBCL user mailing list,
(see second message in the thread "Optimizing a simple Common Lisp Gibbs sampler program", that this could be resolved by declaring x to be greater than or zero as follows,
(declare (type (double-float 0.0 *) x))
See the Common Lisp Hyperspec for the relevant documentation about
FLOAT types
and
Interval Designators.
This seems to speed up the code a bit. It is now reliably below 52 seconds, but still, not much of a gain.
This also leaves the notes about
note: doing float to pointer coercion (cost 13)
If this is not fixable for some reason, I'd like to know why. Also, an explanation of what the note means would be interesting, regardless.
Specifically, what does the word pointer mean here? Is this related to the fact that C functions are being called? Also, cost 13 doesn't seem
very useful. What is being measured?
Also, Rainer suggested that it might be possible to reduce consing, which might reduce runtime.
I don't know whether either consing reduction is possible, or whether it would reduce runtime,
but I'd be interested in opinions and approaches. Overall, it seems not much can be done to improve the performance of this function.
Maybe it is too small and simple.
Note that Common Lisp has a THE special operator. It allows you to declare types for expression results. This for example allows you to narrow down types if possible.
For example what is the result of (SQRT somefloat) ? It can be a float, but it could be a complex number if somefloat is negative. If you know that somefloat is always positive (and only then), then you could write (the double-float (sqrt somefloat)). The compiler then might be able to generate more efficient code.
Also note that Common Lisp has OPTIMIZE declarations. If you want fastest code you need to make sure that you set them accordingly. Possibly only for individual functions. Usually it is better than changing optimization globally to be very aggressive.
Common Lisp has a function DISASSEMBLE which lets you look at the compiled code.
Then there is the macro TIME. Interesting information you get from it includes how much consing it does. With double-float arithmetic there is probably a large amount of consing. It would be useful to ask on the SBCL mailing list for help. Maybe someone can tell you how to avoid that consing.
This works for me:
(sqrt (the (double-float 0d0) (+ (* 2d0 x) 2d0)))

Resources