Here are my comments after a brief reading:
First, if you intend to make this library fit for general use, add documentation in comments for the provided functions. See the Racket style guide for examples
Also, if you intend to make this a more general library, don't include default arguments (e.g. for ircbot-connect) unless they make sense for all users. ...
tl;dr: See the bottom of the post for my implementation of the function.
As mentioned in Ben Rudgers's answer, lists should not be treated as vectors, as they are not random-access. That means you should not be using numeric indices, list lengths, etc.
Lists are recursive data structures
Lists are recursive data structures: a list is either an empty list, ...
So, any time you want to write a "helper" recursive function, the standard way to write that is to use a named let. So here's how I might restructure your program (but keeping the same algorithm):
(define (sum-multiples start end)
(let loop ((sum 0)
(cond ((>= i end) sum)
((or (zero? (modulo i 3))
Here are some general points before I start on more specific points:
I don't see any unit tests. Racket programmers often write many unit tests for each function. You can use the module+ construct and rackunit to easily write internal unit tests.
Indentation is important for clarity. I couldn't tell that everything was internal to heap at first because of ...
Better programming practice would be to decompose the problem in such a way that the procedures adhere to the Single Responsibility Principle. In other words, the answer should be obtained by evaluating something like
(sum (filter (multiple-of-any? 3 5) (range 0 1000)))
… which reads just like the problem to be solved.
Here's a set of functions that ...
Winning shouldn't be considered an error. If you want a way to exit from the for-loop, use #:break. But for and set! aren't really idiomatic in Lisp-like languages. Instead, it is more common to use recursion and let, which conform to the functional programming paradigm.
In num_message, you can use a cond instead of nested ifs.
I'm not happy about the ...
Racket tends to use two space indentation rather than Python's four spaces. This keeps code from indenting too far to the right and because Lisps allow multiple expressions on a single line, reduces the issues with lines becoming uncomfortably long. Keep in mind that "left banana"s [ ( ] are also there to help the reader.
The big ...
Avoid stream->list on large lists.
In your prime? function it will create a (large)
list before passing it on to ormap.
There is a stream version of ormap - namedly stream-ormap, and
this will process the stream lazily - i.e. it will only generate
as many elements of the stream which are needed.
Another way to eliminate the ...
Starting at the top, you have a lot of unused imports. Fortunately, DrRacket can tell you which imports are unused, since it will highlight them in red when you hover your mouse over them. Additionally, if you click the Check Syntax button, it will color all the unused imports red. Using that, we can trim the import list down to the following set:
I would change the type of evaluate to return Either String Expression. This also leads to using the Monad to structure the functions.
As an example:
evaluate :: Env -> Expression -> Either String Expression
evaluate env (Add aExpr bExpr) = do
aValue <- evaluate env aExpr -- if either of these two evaluates fail this call
bValue <- ...
As noted in the comment, your code currently looks like it has a (admittedly fairly minor) problem. In sum-multiples, you try to pass actual and limit as parameters to sum-multiples-rec, but those names aren't bound to anything at that point. You need/want something more like:
(define (sum-multiples lower-limit upper-limit)
Here are some tips that may help. Note that these are collected from feedback on #racket on irc.freenode.net (which you may find helpful too).
The length of the bytestring is counted inside the loop, but it's a loop invariant that you can hoist out of the loop.
Folding over j may be faster than mutating it as you are doing. See Mutation and Performance in ...
It took me a while to see why your second form made sense; it seemed like the Wrong thing until I thought about having a general mechanism to allow later sequences to be closed over the values produced by earlier ones in the way that for* allows. It does have a strongly monadic feel, and ... hmmm...
Actually, one issue I do notice is that in order ...
As you suspected, you don't need append for this problem. The trick is to notice that if, for example, your goal is to create the list '(1 2 3), then writing (list 1 2 3) is more straight-forward and more efficient than writing (append '(1) '(2) '(3)).
With that in mind, consider the following insertion function:
(define (insert BST n)
There are significant issues here:
; draw-rocket: rocket scene --> scene
; Purpose: To draw the given rocket in the given scene
(define (draw-rocket a-rocket a-scene)
(place-image rocket-img a-rocket ROCKET-Y a-scene))
Why break the pattern from drawing code for the others? Use (pos-x a-rocket), (pos-y a-rocket) instead of a-rocket ROCKET-Y. That will ...
You can rewrite all your any- functions in one definition like this
(define (any predicate? a-loa)
(cond [(empty? a-loa) false]
[else (or (predicate? (first a-loa))
(any predicate? (rest a-loa)))]))
There is also a findf function in standard library
; alien-at-edge?: alien --> boolean
(define (alien-at-edge? an-alien)
(or (alien-at-right-edge? an-alien)
Not much to do here but don't forget about indentation to make your code readable.
; any-alien-at-edge?: loa --> boolean
(define (any-alien-at-edge? a-loa)
(cond [(empty? a-loa) false]
[else (or (alien-at-edge? ...
Check this Stack Overflow question out, which has a solution to the same problem. A simplified version would look like this
(define (insert-at pos elmt lst)
(if (empty? lst) (list elmt)
(if (= 1 pos)
(cons elmt lst)
(cons (first lst)
(insert-at (- pos 1) elmt (rest lst))))))
(define (insert-everywhere sym los)
(map (lambda (i)
Overall, this is very pleasant code to review. Especially given you're new to the language. Your function names are follow convention such as the use of ending predicates with ? and indicating conversions with ->. The comments make this code easy to understand. So bravo, keep at it! That being said, here are some pretty minor suggestions.
I see a few points that seem open to improvement.
First of all, in some cases you document the "contract" based on the type of the input and output ("number -> number") but in others the unit of measure ("Miles -> furlongs").
The units of measure are already documented directly in the function's name, so the type is the only one that really makes much ...
Your code doesn't actually work, because your two lambdas both used x as the parameter name, and the inner one shadows the outer one. Here's a fixed version:
(define (tridiagonal n)
By the way, the fastest way to see if a number is divisible by three is to use (zero? (remainder n 3)). If you want to do the digit summing for fun, fine, but it will make your code slower.
So, one way to sum the digits is to extract digits directly during the summing process, rather than building a list of digits first.
(define (digisum n)
(let loop ((...
Well, take this with a grain of salt, as I have a lot less knowledge of
(typed) Racket; that said it's very readable, the comments are nice and
you have a few test, looks good I think.
I'd suggest a few really minor things:
Consistency: At some points you use (list (cons ..., at others the
backquote syntax; I'd probably use only one of them.
Here are my review comments on the tokeniser:
It's unusual to prefix symbols with -. The indentation should be enough to tell you the "nesting level" of the inner functions, without having to put -s in front.
Your inner -tokenize could be hoisted into a named let, so that your tokenize function looked like this (I will make other changes to the function ...
For cases where the the user follows the syntax and the function returns and receives the correct number of values, this works fine.
It is a good principle to catch errors as early as possible.
Consider this example:
Here the user supplies a function add1 that has arity 1, but supplies no arguments. This will eventually lead to an "...
Many Lisp programs use cons cells quite liberally instead of adding a
separate stack structure, in that sense your concerns about complexity
are probably a bit less critical. Since the stack is also carrying the
length of the list it actually supports at least the additional size
operator quite well. Of course writing more code for an underlying
When writing macros, it is best to avoid using functions like datum->syntax to conjure up identifiers. Instead, your macro should take the identifiers to bind from the macro use site.
For your example, I would write it like this:
(provide square total)
;; note how `n` is passed in as an argument
(define-syntax-rule (induction n base rule)
Racket isn't my Lisp of choice, but here's some general advice.
You're calling the function guess multiple times with the same arguments. The code would be much more readable (and slightly more efficient) if you bind the result to a local variable:
(define (game-iter number)
(define (iter number count lower-boundary upper-boundary accu)
(let ((guess (...
The idea of functionally generating the next value from the current value rather than mutating a location is consistent with good Racket practice.
Instead of 0 1 2 3 using the symbols 'north...it's not obvious what comes next without taking notes and working through the code and figuring out the implementation details...'south '...