How to write to stdout within a conditional expression in MIT-Scheme? - scheme

Here is an example of an attempt to write a different string to stdout depending on the value of a variable:
(let ((x 1))
(cond ((< x 2)
(display "hooray"))
(else
(display "bummer")))
)
Notice that the correct string does get written, but we also get an "Unspecified return value"
My understanding is that this happens because the interpreter is trying to return the value of the "consequent expression" of the clause as the value of the conditional, but the "display" expression does not return any value.
Is there a better way of doing this?

Given that this expression is evaluated only for its effect (printing a message), you should explicitly return a value (any value!) as the result of the let form:
(let ((x 1))
(cond ((< x 2)
(display "hooray")
(newline))
(else
(display "bummer")
(newline)))
'ok)
Now we'll get:
hooray
'ok

Related

How to parse a function into another function in scheme

I am trying to create a function that takes another function as a parameter and calls the functions in a loop.
The code below should get the function and the number of times the loop should execute:
(define (forLoop loopBody reps)
(let
(
(fun (car loopBody))
(str (cdr loopBody))
)
(cond
((eval (= reps 0) (interaction-environment)) "")
(else (cons str (forLoop '(fun str) (- reps 1))))
)
)
)
The code below is how i am calling the function
(define (printermsg)
(display msg)
)
(forLoop '(printer "text ") 4)
The expected output for the above code:
text text text text
There are several issues with your code:
The way you pass the loopBody parameter to your function is incorrect, a list of symbols will not work: you want to pass along a list with the actual function and its argument.
You are not obtaining the second element in the list, cdr won't work because it returns the rest of the list, you need to use cadr instead.
Avoid using eval, it's not necessary at all for what you want, and in general is a bad idea.
Why are you building a list? cons is not required here.
When calling the recursion, you are again passing a list of symbols instead of the proper argument.
You're not actually calling the function!
This should work:
(define (forLoop loopBody reps)
(let ((fun (car loopBody))
(str (cadr loopBody)))
(cond
((= reps 0) (void)) ; don't do anything when the loop is done
(else
(fun str) ; actually call the function!
(forLoop loopBody (- reps 1))))))
(define (printer msg)
(display msg))
(forLoop (list printer "text ") 4) ; see how to build the loop body
=> text text text text

Printing in Scheme

I am having some difficulty printing a string in scheme after using a condition and get the following error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: #t
arguments...:
I can't seem to figure out what is wrong with it and would appreciate any help.
(define (neg int)
(cond
(((< int 0) (display "negative"))
(* int (-1)))))
You have too many brackets at the start of your condition; you need two, not three. Remember that in Scheme, if you surround something between () that becomes a function application! That's why this doesn't make sense: (-1), because -1 is not a function, it's a number. Also, what will you do if the value is not negative? You need to handle that case, too! Try this:
(define (neg int)
(cond ((< int 0)
(display "negative ")
(* int -1)) ; or better: (- int)
(else
(display "positive ")
int)))

LISP clause for and clause let ¿why?,making a programming language in racket using ragg

I have long been trying to find the error, I'm doing a programming language and have the next code, using ragg, I have a syntax-object(resto ...) what has a bracket as data, I transform this syntax-object to a datum:
(let ([i (syntax->datum #'(resto ...))])
(display "Content i:")
(display i)
(if (eq? i (string->symbol "(})"))
(display "true")
(display "false")
)
)
and the output is:
Content: (})
false
But if I do this
(for ([i (syntax->datum #'(resto ...))])
(displayln "Content:")
(displayln i)
(if (eq? i (string->symbol "}"))
(display "true")
(display "false")
)
)
and the output is:
Content: }
true
MY QUESTION:
¿WHY THE IF OF CLAUSE LET IS FALSE?
¿AS I CAN COMPARE THESE TWO TYPES AND THAT THE RESULT IS TRUE WITHOUT THE FOR?
Documentation about functions:
syntax->datum
Each piece of code is doing a very different thing, I'll show you how to make each one work. The first one uses let to assign into a variable the whole list returned by syntax->datum, and afterwards you compare it against another list (better use equal? for testing equality, it's more general):
(let ([i (syntax->datum #'(|}|))]) ; `i` contains `(})`
(display "Content i: ")
(displayln i)
(if (equal? i '(|}|)) ; a list with a single element, the symbol `}`
(displayln "true")
(displayln "false")))
The second piece of code is using for to iterate over each element in a list, until it finds the symbol }:
(for ([i (syntax->datum #'(|}|))]) ; `i` contains `}`
(display "Content i: ")
(displayln i)
(if (equal? i '|}|) ; the symbol `}`
(displayln "true")
(displayln "false")))
As a side note, you have to be very careful with the way you're going to process all those curly brackets {} in your language, they're interpreted as normal parentheses () in Racket and they'll be tricky to handle, notice how I had to escape them by surrounding them with vertical bars.

Getting #<undef> back when calling a scheme function

I have the following code in Scheme:
(define (processExpression lst)
(define operand (car lst))
(define operator1 (cadr lst))
(define operator2 (caddr lst))
(if (list? operand)
(begin
(display "Invalid syntax! Erroring out!")
(quit)
)
)
(if (and (number? operator1) (number? operator2))
;The list was of the form (operand c1 c2)
(simplePrefix lst)
)
(if (and (list? operator1) (number? operator2))
(begin
(list operand operator2 (processExpression operator1))
)
)
)
(define (simplePrefix lst)
(let (
(operand (car lst))
(operator1 (cadr lst))
(operator2 (caddr lst)))
(list operator1 operand operator2)
)
)
(display "Please enter a valid s-expression")
(let ((input (read)))
(display (simplePrefix input))
)
This code takes and s-expression and converts it based on some rules. One rule should be that the expression (+ (+ 1 2) 2) should return (+ 2 (1 + 2)).
Currently when I call this code with that expression I get back the result "#undef>" but I have no idea why. The code should call the simplePrefix function on the (+ 1 2) part of the expression and return (1 + 2) but it does not. Does anyone understand why?
The value of
(if condition
something)
is undefined if condition is false, because there's no else part in the if form. In the R5RS version of Scheme, this is stated (emphasis added):
4.1.5 Conditionals
syntax: (if <test> <consequent> <alternate>)
syntax: (if <test> <consequent>)
Syntax: <Test>, <consequent>, and <alternate> may be arbitrary expressions.
Semantics: An if expression is evaluated as follows: first, <test> is evaluated. If it yields a true value (see section
6.3.1), then <consequent> is evaluated and its value(s) is(are) returned. Otherwise <alternate> is evaluated and its value(s)
is(are) returned. If <test> yields a false value and no
<alternate> is specified, then the result of the expression is
unspecified.
(if (> 3 2) 'yes 'no) ===> yes
(if (> 2 3) 'yes 'no) ===> no
(if (> 3 2)
(- 3 2)
(+ 3 2)) ===> 1
Some Scheme-like languages (e.g., Racket) will actually warn you if you try this:
Welcome to Racket v6.1.
> (if #t
(display "hello"))
stdin::1: if: missing an "else" expression
in: (if #t (display "hello"))
context...:
In Common Lisp, the else part is optional, and defined to be nil if not provided:
This is SBCL 1.2.4.58-96f645d, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
* (if t
(print 'hello))
HELLO
HELLO
* (if nil
(print 'hello))
NIL
The expression
(if condition result)
is not equivalent to
if condition
return result
in other languages.
It doesn't return a value, it has a value.
If the condition is false, that value is undefined.
If it is followed by other expressions in a sequence, the value is ignored and the following expressions are evaluated.
The result of evaluating a function application is the value of the last expression in the function's body
(define (foo)
(if (= 1 1)
"one is one")
"I am still here")
> (foo)
"I am still here"
These two added together lead to the error you're experiencing.

Scheme: overload built-in procedures, general overloading

More specifically, can you overload the built-in Scheme procedure display?
More generally, how can you overload any procedure in Scheme?
Scheme doesn't have overloading based on types a`la Java/C++, it's dynamically typed so it wouldn't make sense.
You can do a few things though:
You can overload based on the structure of the arguments:
(define overload1
(case-lambda
((x y) (+ x y))
((x y z) (+ (- x y) z))))
This doesn't really help you though since display is only going to take one argument no matter what.
(define (overload-kinda x)
(cond
((list? x) (do-list x))
((symbol? x) (do-sym x))
;etc
))
Which is hacky but sometimes necessary.
My usual approach is higher order functions and the case lambda
(define my-display
(case-lambda
((x) (display x))
((x f) (display (f x)))))
Now if we need special treatment for displaying anything we pass in a function to render it.
The accepted answer don't overload the function, only define different function with same behavior.
Scheme usually allow to overwrite bultin function, so to overload the function (e.g. display) you can use something called Monkey Patch:
(define display (let ((orig display))
(lambda (x . rest)
(let ((port (if (null? rest)
(current-output-port)
(car rest))))
(if (number? x)
(orig (string-append "#<" (number->string x 16) ">") port)
(orig x port))))))
and now the display work differently with numbers. you can also use custom types like display different type of records in specific way. This is general example how to overwrite bultin function in any language that allow to modify the original binding. You save original function in variable, redefine the function and if you what to call original function you use the variable where you saved original.
The code can be abstracted away into general macro that will redefine the function and run your code on specific types of arguments, so it would be proper overloading like in Java and not only based on number of arguments like in case-lambda.
Here is example such macro (using lisp type macro):
(define-macro (overload name-spec . body)
(let ((name (car name-spec))
(args (cdr name-spec)))
`(define ,name (let ((,name ,name))
(lambda ,args
,#body)))))
(overload (display x . rest)
(let ((port (if (null? rest)
(current-output-port)
(car rest))))
(if (number? x)
(display (string-append "#<" (number->string x 16) ">") port)
(display x port))))
(display 10)
;; ==> #<a>
(display "20")
;; ==> 20

Resources