Racket- converting daily used + - * / - racket

I have encountered a problem where I would want to evaluate a math equation, let's say a list of string ' (1 + 2) and convert it into (+ 1 2) so that racket can solve it. Apparently, you can not simply do ('+ 1 2) as '+is not a procedure.
What are some ways to do it?

After transforming the expression from infix to prefix notation, just use eval:
(define ns (make-base-namespace))
(eval (list '+ 1 2) ns)
=> 3
Of course the usual warning applies, eval is evil, etc. But it's ok for learning purposes, as long as you're aware that most of the time you should not use it in real-life programs.

Related

Is there a way to get information about a module at read time?

I've since this summer played around with making a toy language in Racket. Every form has a fixed arity and by default applies so parentheses are not needed. eg. + has arity 2 so + 3 + 4 5 is (+ 3 (+ 4 5)) and + + 3 4 5 is (+ (+ 3 4) 5).
To do this I'm storing in the main module the symbols and their arity. The reader doesn't care if it's a special form or procedure, but is there a better way to do this using features from racket? Thus I can import a module metadata and query that instead during parsing?
Here is one way to go from symbol to arity.
#lang racket
(define base-ns (make-base-namespace))
(define (symbol->arity s)
(parameterize ([current-namespace base-ns])
(procedure-arity (namespace-variable-value s))))
(symbol->arity 'cons)

Runtime pattern matching in Racket

If Racket's match macro were a function I could do this:
(define my-clauses (list '[(list '+ x y) (list '+ y x)]
'[_ 42]))
(on-user-input
(λ (user-input)
(define expr (get-form-from-user-input user-input)) ; expr could be '(+ 1 2), for example.
(apply match expr my-clauses)))
I think there are two very different ways to do this. One is to move my-clauses into macro world, and make a macro something like this (doesn't work):
(define my-clauses (list '[(list '+ x y) (list '+ y x)]
'[_ 42]))
(define-syntax-rule (match-clauses expr)
(match expr my-clauses)) ; this is not the way it's done.
; "Macros that work together" discusses this ideas, right? I'll be reading that today.
(on-user-input
(λ (user-input)
(define expr (get-form-from-user-input user-input)) ; expr could be '(+ 1 2), for example.
(match-clauses expr)))
The alternative, which might be better in the end because it would allow me to change my-clauses at runtime, would be to somehow perform the pattern matching at runtime. Is there any way I can use match on runtime values?
In this question Ryan Culpepper says
It's not possible to create a function where the formal parameters and body are given as run-time values (S-expressions) without using eval.
So I guess I'd have to use eval, but the naive way won't work because match is a macro
(eval `(match ,expr ,#my-clauses) (current-namespace))
I got the desired result with the following voodoo from the guide
(define my-clauses '([(list'+ x y) (list '+ y x)]
[_ 42]))
(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))
(eval `(match '(+ 1 2) ,#my-clauses) ns) ; '(+ 2 1)
Is the pattern matching happening at runtime now? Is it a bad idea?
To answer the first part of your question (assuming you don't necessarily need the match clauses to be supplied at runtime):
The key is to:
Define my-clauses for compile time ("for syntax").
Reference that correctly in the macro template.
So:
(begin-for-syntax
(define my-clauses (list '[(list '+ x y) (list '+ y x)]
'[_ 42])))
(define-syntax (match-clauses stx)
(syntax-case stx ()
[(_ expr) #`(match expr #,#my-clauses)]))
The pattern matching is happening at runtime in the last example.
One way to check is to look at the expansion:
> (syntax->datum
(expand '(eval `(match '(+ 1 2) ,#my-clauses) ns)))
'(#%app eval (#%app list* 'match ''(+ 1 2) my-clauses) ns)
Whether is a good idea...
Using eval is rather slow, so if you call it often it might be better to find another solution. If you haven't seen it already you might want to read "On eval in dynamic languages generally and in Racket specifically." on the Racket blog.
Thank you both very much, your answers gave me much food for thought. What I am trying to do is still not very well defined, but I seem to be learning a lot in the process, so that's good.
The original idea was to make an equation editor that is a hybrid between paredit and a computer algebra system. You enter an initial math s-expression, e.g. (+ x (* 2 y) (^ (- y x) 2). After that the program presents you with a list of step transformations that you would normally make by hand: substitute a variable, distribute, factor, etc. Like a CAS, but one step at a time. Performing a transformation would happen when the user presses the corresponding key combination, although one possibility is to just show a bunch of possible results, and let the user choose the new state of the expression amongst them. For UI charterm will do for now.
At first I thought I would have the transformations be clauses in a match expression, but now I think I'll make them functions that take and return s-expressions. The trouble with choosing compile time vs runtime is that I want the user to be able to add more transformations, and choose his own keybindings. That could mean that they write some code which I require, or they require mine, before the application is compiled, so it doesn't force me to use eval. But it may be best if I give the user a REPL so he has programmatic control of the expression and his interactions with it as well.
Anyway, today I got caught up reading about macros, evaluation contexts and phases. I'm liking racket more and more and I'm still to investigate about making languages... I will switch to tinkering mode now and see if I get some basic form of what I'm describing to work before my head explodes with new ideas.

Standard way for breaking out of recursion in scheme

I am writing my first program in scheme. I get pretty deep into recursion because I basically interpret a program for a simple robot which can have nested procedure calls.
If I find a violation I need to stop interpreting the program and return the last valid state.
I've solved it by declaring a global variable (define illegalMoveFlag 0) and then setting it via set!.
It works fine, but I guess my tutor won't like it (because it's not functional approach I guess)
Other approach I've thought about is to add an error parameter to every function I call recursively in the program. I don't quite like it because it would make my code far less readable, but I guess it's more 'functional'.
Is there maybe a third way I didn't think about? And can my approach be justified in this paradigm, or is it basically a code smell?
Since this was your first Scheme program, you probably just need to introduce a conditional expression, cond, in order to avoid further recursion when you reach the end. For example:
; sum : natural -> natural
; compute the sum 0+1+...+max
(define (sum max)
(define (sum-helper i sum-so-far)
(if (> i max)
sum-so-far
(sum-helper (+ i 1) (+ sum-so-far i))))
(sum-helper 0 0))
(display (sum 10))
(newline)
However, if you need a traditional return to return like longjmp in C, you will need to store and use an escape continuation. This can be done like this:
(define (example)
(let/ec return
(define (loop n)
(if (= n 100000)
(return (list "final count: " n))
(loop (+ n 1))))
(loop 0)))
(display (example))
If let/ec is not defined in your Scheme implementation, then prefix your program with:
(define-syntax let/ec
(syntax-rules ()
[(_ return body ...)
(call-with-current-continuation
(lambda (return)
body ...))]))
UPDATE:
Note that cond has an => variant:
(cond
[(call-that-can-fail)
=> (lambda (a) <use-a-here>))]
[else <do-something-else>])
If the call succeeds then the first, clause is
taken and the result is bound to a. If the call fails,
then the else clause is used.
The usual way to stop recursing is, well, to stop recursing. i.e., don't call the recursive function any longer. :-)
If that is too hard to do, the other way to break out of something is to capture a continuation at the top level (before you start recursing), then invoke the continuation when you need to "escape". Your instructor may not like this approach, though. ;-)
You might want to use the built-in procedure error, like so:
(error "Illegal move") ; gives ** Error: Illegal move
This will raise an exception and stop interpreting the program (though I suspect this may not be what you are looking for).
You can also provide additional arguments, like this:
(error "Illegal move: " move) ; gives ** Error: Illegal move: <move>
You can exit of a recursion (or from any other process) using a continuation. Without knowing more specifics, I'd recommend you take a look at the documentation of your interpreter.
Make illegalMoveFlag a paramter in the function instead of a global variable
I'll give you a simple example with factorials
ie:
0! = 1
n! = n * (n - 1)! when n (1 ... infinity)
lets call this a recursive factorial
(define (fact-r n)
(if
[eq? n 0]
1
(* n (fact-r (- n 1)))
)
)
An alternative would be to use a parameter to the function to end the recursion
Lets call it iterative factorial
(define (fact-i n total)
(if
(eq? n 0)
total
(fact-i (- n 1) (* n total))
)
)
total needs to start at 1 so we should make another function to make using it nicer
(define (nice-fact n)
(fact-i n 1))
You could do something similar with illegalMoveFlag to avoid having a global variable
As far as avoiding using set! goes, we'll probably need more information.
In some cases its still rather hard to avoid using it. Scheme is fully turing complete without the use of set! however when it comes to accessing an external source of information such as a database or a robot set! can become the only practical solution...

What is the difference between 1 and '1 in Lisp?

I had never really thought about whether a symbol could be a number in Lisp, so I played around with it today:
> '1
1
> (+ '1 '1)
2
> (+ '1 1)
2
> (define a '1)
> (+ a 1)
2
The above code is scheme, but it seems to be roughly the same in Common Lisp and Clojure as well. Is there any difference between 1 and quoted 1?
In Common Lisp, '1 is shorthand for (QUOTE 1). When evaluated, (QUOTE something) returns the something part, unevaluated. However, there is no difference between 1 evaluated and 1 unevaluated.
So there is a difference to the reader: '1 reads as (QUOTE 1) and 1 reads as 1. But there is no difference when evaluted.
Numbers are self-evaluating objects. That's why you don't have to worry about quoting them, as you do with, say, lists.
A symbol can be made from any string. If you want the symbol whose name is the single character 1, you can say:
(intern "1")
which prints |1|, suggesting an alternate way to enter it:
'|1|
Quoting prevents expressions from being evaluated until later. For example, the following is not a proper list:
(1 2 3)
This is because Lisp interprets 1 as a function, which it is not. So the list must be quoted:
'(1 2 3)
When you quote a very simple expression such as a number, Lisp effectively does not alter its behavior.
See Wikipedia: Lisp.
Well, they are in fact very different. '1 is however precisely the same as (quote 1). (car ''x) evaluates to the symbol 'quote'.
1 is an S-expression, it's the external representation of a datum, a number 1. To say that 1 is a 'number-object' or an S-expression to enter that object would both be acceptable. Often it is said that 1 is the external representation for the actual number object.
(quote 1) is another S-expression, it's an S-expression for a list whose first element is the symbol 'quote' and whose second element is the number 1. This is where it's already different, syntactic keywords, unlike functions, are not considered objects in the language and they do not evaluate to them.
However, both are external representations of objects (data) which evaluate to the same datum. The number whose external representation is 1, they are however most certainly not the same objects, the same, code, the same datum the same whatever, they just evaluate to the very same thing. Numbers evaluate to themselves. To say that they are the same is to say that:
(+ 1 (* 3 3))
And
(if "Strings are true" (* 5 (- 5 3)) "Strings are not true? This must be a bug!")
Are 'the same', they aren't, they are both different programs which just happen to terminate to the same value, a lisp form is also a program, a form is a datum which is also a program, remember.
Also, I was taught a handy trick once that shows that self-evaluating data are truly not symbols when entered:
(let ((num 4))
(symbol? num) ; ====> evaluates to #f
(symbol? 'num) ; ====> evaluates to #t
(symbol? '4) ; ====> evaluates to #f
(symbol? '#\c) ; #f again, et cetera
(symbol? (car ''x)) ; #t
(symbol? quote) ; error, in most implementations
)
Self evaluating data truly evaluate to themselves, they are not 'predefined symbols' of some sorts.
In Lisp, the apostrophe prevents symbols to be evaluated. Using an apostrophe before a number is not forbidden, it is not necessary as the numbers represent themselves. However, like any other list, it automatically gets transformed to an appropriate function call. The interpreter considers these numbers coincide with their value.
As has been pointed out, there is no difference, as numbers evaluate to themselves. You can confirm this by using eval:
(eval 1) ;=> 1
This is not limited to numbers, by the way. In fact, in Common Lisp, most things evaluate to themselves. It's just that it's very rare for something other than numbers, strings, symbols, and lists to be evaluated. For instance, the following works:
(eval (make-hash-table)) ;equivalent to just (make-hash-table)
In Lisp, quote prevent the following expression to be evaluated. ' is a shorthand for quote. As a result, '1 is same as (quote 1).
However, in Lisp, symbols can never be a number. I mean, 'abc is a symbol, but '123 is not (evaluated into) a symbol. I think this is wrong of the design of Lisp. Another case is not only #t or #f can be used as a Boolean expression.

Which is better?: (reduce + ...) or (apply + ...)?

Should I use
(apply + (filter prime? (range 1 20)))
or
(reduce + (filter prime? (range 1 20)))
Edit: This is the source for prime in clojure from optimizing toolkit.
(defn prime? [n]
(cond
(or (= n 2) (= n 3)) true
(or (divisible? n 2) (< n 2)) false
:else
(let [sqrt-n (Math/sqrt n)]
(loop [i 3]
(cond
(divisible? n i) false
(< sqrt-n i) true
:else (recur (+ i 2)))))))
If you are asking in terms of performance, the reduce is better by a little:
(time (dotimes [_ 1e6] (apply + (filter even? (range 1 20)))))
"Elapsed time: 9059.251 msecs"
nil
(time (dotimes [_ 1e6] (reduce + (filter even? (range 1 20)))))
"Elapsed time: 8420.323 msecs"
nil
About 7% difference in this case, but YMMV depending on the machine.
You haven't provided your source for the prime? function, so I have substituted even? as the predicate. Keep in mind that your runtime may be dominated by prime?, in which case the choice between reduce and apply matters even less.
If you are asking which is more "lispy" then I would say that the reduce implementation is preferrable, as what you are doing is a reduce/fold in the functional programming sense.
I would think that reduce would be preferable when it is available, because apply uses the list as arguments to the function, but when you have a large number -- say, a million -- elements in the list, you will construct a function call with a million arguments! That might cause some problems with some implementations of Lisp.
(reduce op ...) is the norm and (apply op ...) the exception (notably for str and concat).
I would expect apply to realize a lazy list which could be ugly, and you never want to assume your list is not lazy, 'cause you could suddenly find yourself getting smacked with massive memory useage.
Reduce is going to grab them 1 by one and roll the results together into a single whole, never taking the whole list in at once.
i am going to play devil's advocate and argue for apply.
reduce is clojure's take on fold (more exactly foldl), the left-fold, and is usually defined with an initial element, because a fold operation has two parts:
an initial (or "zero") value
an operation for combining two values
so to find the sum of a set of numbers the natural way to use + is as (fold + 0 values) or, in clojure, (reduce + 0 values).
this explicitly shows the result for an empty list, which is important because it is not obvious to me that + returns 0 in this case - after all, + is a binary operator (all that fold needs or assumes).
now, in practice, it turns out that clojure's + is defined as more than a binary operator. it will take many or, even, zero values. cool. but if we're using this "extra" information it's friendly to signal that to the reader. (apply + values) does this - it says "i am using + in a strange way, as more than a binary operator". and that helps people (me, at least) understand the code.
[it's interesting to ask why apply feels clearer. and i think it's partly that you are saying to the reader: "look, + was designed to accept multiple values (that's what apply is used for), and so the language implementation will include the case of zero values." that implicit argument is not present with reduce applied to a single list.]
alternatively, (reduce + 0 values) is also fine. but (reduce + values) triggers an instinctive reaction in me: "huh, does + provide a zero?".
and if you disagree, then please, before you downvote or post a reply, are you sure about what (reduce * values) will return for an empty list?
I agree with Andrew Cooke. But I would like to add that since it already knows how to work and handle multiple arguments, we are essentially re-telling the '+' operator how to work by using it in the 'reduce', in my opinion.
Also, if I told you do to add a bunch of numbers together, you would probably use the '+' operator by itself, and not use 'reduce' at all.
(+ 1 2 3 etc...)
'apply' is just saying, I want to do the same thing, but use what's inside this list for the arguments. There is no extra reasoning required and you are using it as if the numbers didn't exist in a list to begin with, like you would if you were writing it out yourself.
(Reduce is so heavily used that using/reasoning about it in this case isn't a big deal at all, I think either way is fine, but personally prefer apply)