Applying a symbol as a procedure - scheme

Suppose I have a simple symbol:
> '+
+
Is there any way I can apply that symbol as a procedure:
> ((do-something-with '+) 1 2)
3
So that '+ is evaluated to the procedure +?

I'm not 100% sure, but would:
((eval '+) 1 2)
work? I'm not sure if you need to specify the environment, or even if that works - I'm a Scheme noob. :)

Lucas's answer is great. For untrusted input you can make a white list of allowed symbols/operators.
(define do-something (lambda (op)
(cond
((equal? op `+) +)
((equal? op `-) -)
((equal? op `*) *)
((equal? op `/) /)
((equal? op `^) ^))))
((do-something `+) 1 2)

Newbie too so hope I've understood your question correctly...
Functions are first class objects in scheme so you don't need eval:
1 ]=> (define plus +)
;Value: plus
1 ]=> (plus 2 3)
;Value: 5
HTH
Update: Ignore this and see the comments!

Related

User input to a list

I'm trying to take in user input and add it to a list but I have not been able to get it working. I'm still new to scheme and have been browsing around to try to figure it out but I haven't had any luck.
(display "Continue to enter numbers until satisfied then enter e to end")
(newline)
(define (intlist number)
(define number(read-line))
(cond (number? number)
(cons lst (number))
(else
(display lst)
done')))
this is what I have so far. Any help or direction to where I can learn a bit more is appreciated.
Your solution is almost correct, but it doesn't work, because:
Variable lst doesn't exist and with this expression (number), you are calling some undefined function number.
done' is badly written 'done.
Function cons expects element as first argument and other element or list as second argument.
See these examples:
> (cons 1 2)
'(1 . 2)
> (cons 1 '())
'(1)
> (cons 1 (cons 2 (cons 3 '())))
'(1 2 3)
Last example is important here- your function will be recursive and it will return a cons cell in each step. If I will follow your solution, this can be enough:
(define (list-from-user)
(let ((number (read)))
(if (number? number)
(cons number (list-from-user))
'())))
(Note that I used read instead of read-line, because read-line returns string, and let instead of define.)
If you really want to wait for e, you must decide, what happens if user enters something that isn't number and isn't e- maybe just ignore it?
(define (list-from-user)
(let ((user-input (read)))
(cond ((number? user-input) (cons user-input (list-from-user)))
((eq? user-input 'e) '())
(else (list-from-user)))))
Then just add some wrapping function with output:
(define (my-fn)
(begin (display "Continue to enter numbers until satisfied then enter e to end")
(newline)
(list-from-user)))
and call it
> (my-fn)
Note that my function returns list with numbers, instead of some useless 'done, so I can use that function in other functions.
(define (sum-of-list)
(let ((lst (my-fn)))
(format "Sum of given list is ~a." (apply + lst))))
> (sum-of-list)

Printing intermediate results in Scheme

I want to make a program that makes a conversion simulating a for loop, for example:
orig value converted
1 2.2
2 4.4
...
199 437.8
So far, what I have done is the following:
(define (conv ini)
(if (> ini 199)
0
(begin(
(display (* ini 2.2))
(newline)
(conv (+ ini 1))))))
but when I want to run it I got the following error:
arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 2
arguments...:
I see that my recursion call is fine, so I cannot get it which one is the problem.
The syntax of begin is (begin form ...) not (begin (form ...)): your function should be
(define (conv ini)
(if (> ini 199)
0
(begin
(display (* ini 2.2))
(newline)
(conv (+ ini 1)))))
(Or, if you are enamoured of a syntax like that, you could define
(define-syntax beguine
(syntax-rules ()
[(_ (form ...))
(begin form ...)]))
and then (beguine (...)) will work.)
...
(begin(
(display (* ini 2.2))
...))))
In your code you actually try to execute (OP ...), where OP is the value of (display ...), which for sure is not a function.
So I doubt a lot your output is the output of what you pasted in your question.

Scheme: cannot use #t in an if statement

Apologies if the question title is a bit confusing. Maybe after you are through reading it, you can suggest me a better title.
As a part of a homework assignment for an online course, I wrote an iterative procedure in mit-scheme to display number from 1 to a given number.
The code below works fine:
(define (count2-iter num)
(define (iter counter)
(cond ((> counter num) #t)
(else (display counter)
(iter (+ counter 1)))))
(iter 1))
The output:
1 ]=> (load "count2-iter.scm")
;Loading "count2-iter.scm"... done
;Value: count2-iter
1 ]=> (count2-iter 10)
12345678910
;Value: #t
Personally I do not like using cond for 2 branches only and I tried to use if for this.
(define (count2-iter1 num)
(define (loop idx)
(if (> idx num)
#t
((display idx)
(loop (+ idx 1)))))
(loop 1))
The output:
1 ]=> (count2-iter1 5)
5
;The object #!unspecific is not applicable.
;To continue, call RESTART with an option number:
; (RESTART 2) => Specify a procedure to use in its place.
; (RESTART 1) => Return to read-eval-print level 1.
Why is this? Shouldn't #t be evaluated the same way it was used in cond? Would really appreciate an explanation as I am still new to Scheme.
Try this instead:
(define (count2-iter1 num)
(define (loop idx)
(if (> idx num)
#t
(begin ; notice the difference!
(display idx)
(loop (+ idx 1)))))
(loop 1))
Here's why: when you use an if, there can be only one expression in the consequent part and one in the alternative part. If more than one expression is needed, we have to surround them with a (begin ...). You surrounded the expressions between (...), which is not ok, because parenthesis are used for function application (that's why the error message states that The object #!unspecific is not applicable).
On the other hand, a cond has an implicit begin for each of its clauses when a condition is met. Personally, I prefer to stick with using cond when I need more than one expression after a condition - it's less verbose.

Issues with evaluating expressions from user input

I'm trying to make a recursive definition that reads and execute user expressions, such as (3 + 5). Everything is working, except of one problem with the arithmetic symbol.
I managed to replicate the error in a simpler example:
(define v '(1 + 3))
((cadr v) 2 4)
The (cadr v) is the + symbol, but for some reason the procedure can't be executed on the two arguments that followed. Am I missing something?
I think that's because
(cadr v)
returns '+ not + (literal + not a + function).
You need to evaluate it before applying it to arguments.
This should work:
((eval (cadr v)) 2 4)
^evaluates the '+ to +
edit
This worked in racket in interactive mode.
I'm not really sure what's the difference, but made it work in r5rs mode in racket (a script):
#lang r5rs
;required by r5rs
(define user-initial-environment (scheme-report-environment 5))
(define v '(1 + 2))
;eval expects a quoted expression
;(it seems that if it's a function it has to have arguments too)
;and evaluation environment.
((eval (cadr v) user-initial-environment) 2 4)
As others have pointed out, the problem is that the list you've constructed contains the symbol plus, rather than the function plus.
At its heart, this is the same reason that '(a b) returns a list of two symbols, rather than signalling an unbound identifier error; the quote starts a term in a "data language" where legal identifiers are interpreted as symbols, rather than as variable references.
The question, of course, is what you should do about it. Some here have suggested using 'eval'; this is probably a bad idea, for reasons that I think Matthew Flatt captures elegantly in his blog post on the topic.
Instead, you should probably write a simple mapping function. Here's the way I'd write it. If you use my code in an assignment, be sure to credit me :).
#lang racket
;; a mapping from symbols to operators
(define operator-hash
(hash '+ +
'- -
'* *))
;; ... and whatever other operators you want.
;; example of using it:
(hash-ref operator-hash '+) ;; ==> +
Try this:
(define v '(1 + 3))
(let ((operator (eval (cadr v)))
(operand1 (car v))
(operand2 (caddr v)))
(apply operator (list operand1 operand2)))
You can do it this way with eval in Guile:
(define (infix-eval v)
(eval (list (cadr v)(car v)(caddr v))
(interaction-environment)))
> (infix-eval '(1 + 2))
3
Rather than using interaction-environment, you could supply another environment for evaluation, where you could also define some other symbols not found in standard Scheme, so that expressions like (7 % 3) and (2 ^ 6) would also work.

How can I generate this code in Racket/Scheme?

I want to generate code in the following way:
(define (foo str)
(map (lambda (x) (* 100 x)) (hash-ref dd str)))
(define sth `(begin
(define dd (make-hash (list (cons "L" (list 1 2 3)))))
(hash-set! dd "H" ,(foo "L"))
dd))
(I will write sth to a sth.rkt file and execute it)
However, this doesn't work, because in the code for foo, it references on the dd identifier that is in the generated code, and therefore does not exist yet!
There is a way that I can generate code like this:
(define sth `(begin
(define dd (make-hash (list (cons "L" (list 1 2 3)))))
(hash-set! dd "H" (foo "L"))))
and prepend the function foo, but I don't really want that foo in my final file!
How can I work around this?
Are you sure that you're doing work that really requires code generation? Nothing in the example you've shown us requires it yet, as you can do something like this. In Racket:
#lang racket
;; When this file is required, dd will be provided to the outside.
(provide dd)
(define (foo str)
(map (lambda (x) (* 100 x)) (hash-ref dd str)))
(define dd (make-hash (list (cons "L" (list 1 2 3)))))
(hash-set! dd "H" (foo "L"))
This is a module that can be used by other programs. A module in Racket hides everything except for the items that are provided.
If you can explain why you want to do a code generation approach, maybe that will help us understand the question better. For code generation, a macro approach will probably work better than generating an s-expression and writing it to a file. See: http://docs.racket-lang.org/guide/macros.html for example.

Resources