Reading a file - where does '(#<void> ... #<void>) come from? - scheme

The following code is meant to display read text line-by-line:
#!/usr/bin/env racket
#lang racket/base
(require racket/string)
(require racket/file)
(require racket/file)
(display "Line by line with for loop:\n\n")
(define f "../file-to-be-read.short")
(define content (file->lines f))
(for ([l content]) (display l))
(define (do-sth-to-each-line fn-name)
(define f "../file-to-be-read.short")
(define content (file->lines f))
(map fn-name content))
(display "\n\nAnd now line by line with map and display:\n\n")
(do-sth-to-each-line display)
the code reads from ../file-to-be-read.short whose content is:
Not that I think you did not love your father,
But that I know love is begun by time,
And that I see, in passages of proof,
Time qualifies the spark and fire of it.
The result of the call to (do-sth-to-each-line display) is the following:
Not that I think you did not love your father,But that I know love is begun by time,And that I see, in passages of proof,Time qualifies the spark and fire of it.'(#<void> #<void> #<void> #<void> #<void> #<void> #<void>)
Where does '(#<void> #<void> #<void> #<void> #<void> #<void> #<void>) come from? Why doesn't (for ([l content]) (display l)) produce such unintended by me output?

#<void> is return value for display function, so '(#<void> #<void> #<void> #<void> #<void> #<void> #<void>) is result of map display over content (map and for both produce list of results, so for returns the same result).
If you want to run some side effect for each element in the list, you should rather use for-each.
Also, don't use define inside define, use let for introducing local variables, and consider using displayln:
#lang racket
(require racket/string)
(require racket/file)
(define (print-file filename)
(for-each displayln
(file->lines filename)))
(displayln "Now line by line with for-each and displayln:")
(print-file "../file-to-be-read.short")

A better way to use for for this is:
(define (display-file filename)
(call-with-input-file filename
(lambda (port) (for ([line (in-lines port)]) (display line)))))
in-lines returns a sequence that iterates over lines read from a port one at a time instead of reading the entire file into a list first, making it use a lot less memory on large input files.
There's also display-lines as an alternative to for-each (Which as pointed out by Martin is better than map here), though it too requires the entire input file to be read first:
(display-lines (file->lines filename) #:separator #\u200C)
It just displays every element of the given list, with a separator character between then (Defaults to #\newline making it act like displayln of each element instead of display). In this case to mimic the behavior of the other versions that don't insert anything between lines, U+200C ZERO WIDTH NON JOINER is used as the separator character to get the same visual effect when looking at the output in Unicode-aware programs. #\space is another option, since ZWNJ might cause unexpected effects on non-ASCII text (As can not having a separator between lines).

Related

Why doesn't my program produce any output?

I am looking to write a Scheme function numofatoms that determines the number of elements in a list.
For example, (numOfSymbols '((1 3) 7 (4 (5 2) ) ) should return 6.
What I have so far:
;(1 3) 7 (4(5 2)) the list
(define (numofatoms lst) ;defining a numofatoms function
(define (flatten x) ;defining a flatten function
(cond ((null? x) '())
((pair? x) (append (flatten (car x)) (flatten (cdr x))))
(else (list x))))
(length (flatten lst)))
(numofatoms '((1 3) 7 (4(5 2)))); calling the function
After defining numofatoms and flatten I don't see any errors but the program is not working. It doesn't produce any outputs.
The posted code works fine if you load it and call numofatoms from the REPL. I presume that OP is either calling load from the REPL or running the code as a script from the command-line, and when either of these is done OP sees no output. The REPL evaluates and prints results (hence the P), but when you load code that isn't necessarily what happens.
When an expression is evaluated in the REPL, the value to which the expression evaluates is printed. There may be an expectation that the value of the final expression in a file will be printed when the file is loaded into the REPL, but that expectation will not be rewarded.
The load procedure is not standardized for R6RS; here it is implementation-specific, and the particulars depend upon the implementation. For Chez Scheme, load returns an unspecified value, so there should be no expectation of seeing anything useful when a file is successfully loaded.
Both R5RS and R7RS have load procedures described in the standards, but both leave it unspecified whether the results of evaluating the expressions in a file are printed.
The details of any script mechanism for Scheme programs is entirely dependent upon the implementation. But, when you run a script from the command-line your are not in a REPL, so again there should be no expectation that the results of evaluating various forms in the file will be printed to the terminal window.
If you want a Scheme file or script to print something, you have to make it do that. If the final line of the posted file is changed to (display (numofatoms '((1 3) 7 (4(5 2))))) (newline), the program will display the result of calling numofatoms whenever it is run.

What is the use of 'when' in Scheme?

I'm triying to use when in Scheme but i dont know why at the last element of my list appears .#void>.
Here is my code
(define (genlist x y)
(when
(< x y)
(cons x (genlist (+ x 1) y))))
And this is my output =>
(2 3 4 5 6 7 8 9 . #void>)
We use when when we need to write an if without an else part, and/or when we need to write more than one expression inside the if. Only the last expression's value gets returned, hence we use it mostly for the side effects. To understand it better, in Racket this:
(when <condition>
<exp1>
<exp2>
<exp3>)
Is equivalent to this:
(if <condition>
(begin
<exp1>
<exp2>
<exp3>)
(void)) ; implementation-dependent
The same considerations apply to unless, except that the condition is surrounded with a (not ...).
The source of your problems (and the reason why it's a code smell to have an if without an else) is that your code is not handling the case when (>= x y). Ask yourself, what should you do in that case? Simple, return an empty list! that's the base case of the recursion that's missing from your code.
You would need to use (if (< x y) (cons ...) '()) to produce a proper list.
when (and it's counterpart unless) is mostly for doing side effects (like printing something out) in a context where the result is not used.
e.g. (when debug-mode? (print "got here"))
when is an one armed ifs with implicit begin. The following examples are the same:
(if (any odd? lst)
(begin
(set! some-binding #t)
(display "Found an odd element")))
(when (any odd? lst)
(set! some-binding #t)
(display "Found an odd element"))
And you can use unless instead of using not in the predicate:
(if (not (any odd? lst))
(set! some-binding #f))
(unless (any odd? lst)
(set! some-binding #f))
Peter Norvig made a nice book about Lisp style and in it he addresses this:
Be as specific as your data abstractions warrant, but no more.
if for two-branch expression
when, unless for one-branch statement
and, or for boolean value only
cond for multi-branch statement or expression
So while you can write all your logic using if it will not be the easiest code to read. Other might use the term principle of least surprise. Even though the book is for Common Lisp much of it can be used in Scheme as well. It's a good read if you want to program any lisp dialect professionaly.
For when and unless this is applies much better to Scheme as you have no idea what an implementation might return in the event the predicate evaluates to #f while in CL you could abuse when since it's destined to return nil in such cases.
In you code you are trying to return something and letting the implementation choose what should happen when the predicate failes is what causes the #<void>. When the return matter you should always use two armed if:
(if test-expression
then-expression
else-expression)
Note there is no else keyword.

Syntax Error in Racket equal?

I am trying pass in a list input to conversation and have the function check to see if the first element in another list (keyword) matches to the first element of the list that user passed in. If the two match then output a zero otherwise pass the tail of the inputted list recursively back to itself.
(define keyword '(am I))
(define (conversation input)
(cond
((equal? (car keyword) (car input)) 0)
(else (conversation (cdr input)))))
The error I get is:
car: contract violation
expected: pair?
given: '()
I understand that equal? compares two elements, a pair, but what I do not understand is why it would create an error when the car of both lists are both exactly an element. Any help would be much appreciated, I'm assuming the solution is rather simple but I can't seem to see it.
My goal is create several functions that pattern match and output appropriate dialog but without the use of regular expressions or other libraries. There is no mandate not to use the two mentioned above but I would like to do it without them to get a better understanding of the logic and the code. Thanks for the help!
The first thing to consider is that you have no condition of failure. You assume there's either a match now with the car, or there will be a match later with the cdr. But there may be no match at all, and you will cdr down your list until your list is '(). As there is no such thing as the car of '() you are getting an error when you try to extract it. Therefore the first thing to do is make sure you've handled this case. I don't know what you intend to do in this case, so I have made the procedure return #f.
Next you consider what to do if the symbols do match. In your case you are choosing to return 0. This part seems to have no problems.
Finally, we consider what to do if the cars do not match. In this case we continue searching the input. This part seems to have no problems.
(define (conversation input)
(cond ((null? input) #f)
((eq? (car input) (car keyword))
0)
(else
(conversation (cdr input)))))

Dereference variable inside list

Is it possible to dereference a variable contained inside a list, to obtain its value? For example:
(define one 1)
(define two 2)
(define list '(one two))
(display (list-ref list 0))
Here list-ref references to one, and display shows one in letters. Could instead one dereference to the value contained by the homonym variable?
Eval can definitely solve this problem... but like most situations where eval is applicable, it's a large and dangerous hammer.
Matthew Flatt's blog post on this topic has become the go-to explanation:
http://blog.racket-lang.org/2011/10/on-eval-in-dynamic-languages-generally.html
Here's how you might do it without eval in Racket. Stripping away the cruft, "dict-ref" can find a named
element (or elements) in an "association list".
#lang racket
(define data
'((one 1)
(two 2)))
(define wanted-list '(two one))
;; evaluates to '((2) (1)):
(for/list ([wanted wanted-list])
(dict-ref data wanted))
That's happening because the quoted list contains two symbols, one and two. Try the following:
(display (eval (list-ref list 0)))
To resolve that symbol.

How can I include 'quote inside a list in Scheme?

I am trying to make a list in Scheme like this: (list 'quote 'a) and I expect the output to be (quote a) but the interpreter excutes the quote and the output is: 'a
How can I write the code to get the expected output?
That's as it ought to be, since the expression 'a is an abbreviation for the list (quote a), and the interpreter's printer is using that shorthand for its output. You should note that if you tell the interpreter to evaluate 'a, it prints out a unadorned with an apostrophe.
If you try taking out the parts of (list 'quote 'a), you would see that you have exactly the list you expected to get:
> (car (list 'quote 'a))
quote
> (cadr (list 'quote 'a))
a
So in summary, you are getting the expected output, just not the expected representation. If you truly demand that you get as output (quote a), then you have to look into your interpreter's documentation to see if that's supported. Or you might have to write your own procedure to print out lists.
Which implementation are you using. Changing how the REPL prints out sexps depends on your implementation of scheme, and if the implementation supports writing out sexps in an expanded form.

Resources