I am attempting to read and write a matrix from file "data.txt".
The matrix is lists with strings inside of them.
When I am writing I want to write from the begining an override the data. Basically I delete the file every time. I need bether solusion for this.
May main problem is that after a couple readings and writhings of the file corrupts.
system error: Access is denied.; errno=5
My code:
;reading file returning matix of strings
(define (file-reader file-name)
(define pointer (open-input-file file-name))
(define (helper line)
(cond
((equal? line eof) '())
((cons (list line) (helper (read-line pointer))))))
(list-matr (helper (read-line pointer)))
)
;converting matrix of string to matrix of lists with strings inside
(define (list-matr str-matr)
(define (helper str-matr line-num)
(cond
((null? str-matr) '())
((= line-num 1) (cons (map (lambda (x) (string-append x "?")) (string-split (caar str-matr) "? ")) (helper (cdr str-matr) (+ line-num 1))))
((cons (string-split (caar str-matr) " ") (helper (cdr str-matr) (+ line-num 1))))))
(helper str-matr 1))
;saving in file
(define (writer file-name questions answers)
(cond
((file-exists? file-name) (delete-file file-name)))
(write-to-file file-name (string-append (string-join questions) "\n"))
(define (helper cur-l ans)
(cond
((null? ans))
((helper (write-to-file file-name (string-append (string-join (car ans)) "\n")) (cdr ans)))))
(helper '() answers)
)
(define (write-to-file path string)
(call-with-output-file path #:exists 'append
(lambda (newline)
(display string newline))))
Commands for calling the functions.
(file-reader "data.txt")
(writer "data.txt" questions answers)
I think the problem coming from that I don't close the files, but I can't figure out where to put the command for that.
If my code is very bad you can give me other examples for reading and writing matrix from file.
Thank you.
You are correct that the file will corrupt - it's never properly closed.
Without overwriting the file each time, you will need something outside of the normal R5RS/R7RS-small specification, and I'm not aware off the top of my head of any (final) SRFI that allows random file access. That said, many/most Scheme implementations provide some form of low-level I/O interface. The disadvantage of such is that you will have to track the structure very carefully so as to overwrite or add only the correct amount, which will probably be more work than rewriting the entire file.
I would recommend restructuring this completely. First, the call-with-output-file/with-output-to-file procedures will automatically overwrite the output file unless flagged otherwise (in most implementations - though the specifications state that the behaviour is undefined). They will also automatically close the file upon completion. Similar behaviour for the call-with-input-file/with-input-from-file procedures.
You can probably simplify everything by something like the following:
; reader
; this could be further simplified by replacing the cons call with
; (cons (<parse-procedure> l) r), to parse the input at the same time
(define (matrix-read filename)
(with-input-from-file filename (lambda ()
(let loop ((l (read-line))
(r '()))
(if (eof-object? l)
(reverse r)
(loop (read-line) (cons l r))))))
; I don't understand the input/output format...
; writer
(define (matrix-write filename data)
(with-output-to-file filename (lambda ()
(for-each
(lambda (l)
; again, I don't know the actual structure outside of a list
(display l)
(newline))
data))))
If you explain the input format, I can modify the answer.
Related
could someone help me with clarification to one of the possible solution to exercise 3.19. the procedure mystery is infinite loop in case list cycle is given as argument. nevertheless when we use procedure eq? to check if list contains the cycle, it works and provides true value.
(define (last-pair x)
(if (null? (cdr x))
x
(last-pair (cdr x))
)
)
(define (make-cycle x)
(set-cdr! (last-pair x) x)
)
(define (mystery x)
(define (loop x y)
(if (null? x)
y
(let ((temp (cdr x)))
(set-cdr! x y)
(loop temp x)
)
)
)
(loop x '())
)
(define t (list 1 2 3))
(define w (make-cycle t))
(eq? (mystery t) t)
it looks like magic. I would appreciate for any help.
mystery reverses an array "in-place" by repeatedly snipping off the cdr of each entry and replacing that with the cdr of the previous x.
If this list has no loop, then it will end up reversed by the time you get back to the original '(). If there is a loop, you'll have the original array's pointer.
This is definitely a tricky to understand issue. If you make a box-and-pointer diagram it will definitely help and you'll only need to draw 3 diagrams.
Automatically Generating Diagrams of Lists
In the process of doing SICP myself, I found myself wanting a way to visualize list mutation (and to skip the numerous "draw a list diagram of..." exercises). I wrote a small function for doing so and I thought you might find it helpful if I shared it.
These diagrams are an example of this function being run on x each time loop (within the mystery function) is ran.
The following code is what I used for generating these diagrams. I wrote this code as a Scheme novice, but it's very simple to use: the function (list->graphviz) accepts a parameter lst which is the list you'd like a diagram of, as well as an optional argument graph-name which gives the graph a special name.
(define* (list->graphviz lst #:optional graph-name)
"""Convert a list into a set of Graphviz instructions
`lst' is the list you'd like a diagram of
`graph-name` is an optional parameter indicating the name you'd like to give the graph."""
(define number 0)
(define result "")
(define ordinals '())
(define (result-append! str)
(set! result (string-append result str)))
(define* (nodename n #:optional cell)
(format #f "cons~a~a" n (if cell (string-append ":" cell) "")))
(define* (build-connector from to #:optional from-cell)
(format #f "\t~a -> ~a;~%" (nodename from from-cell) (nodename to)))
(define (build-shape elt)
(define (build-label cell)
(cond ((null? cell) "/");; "∅") ; null character
((pair? cell) "*");; "•") ; bullet dot character
(else (format #f "~a" cell))))
(set! number (+ number 1))
(format #f "\t~a [shape=record,label=\"<car> ~a | <cdr> ~a\"];~%"
(nodename number)
(build-label (car elt))
(build-label (cdr elt))))
(define* (search xs #:optional from-id from-cell)
(let ((existing (assq xs ordinals)))
(cond
;; if we're not dealing with a pair, don't bother making a shape
((not (pair? xs)) (result-append! "\tnothing [shape=polygon, label=\"not a pair\"]\n"))
((pair? existing)
(result-append! (build-connector from-id (cdr existing) from-cell)))
(else
(begin
(result-append! (build-shape xs))
(set! ordinals (assq-set! ordinals xs number))
(let ((parent-id number))
;; make a X->Y connector
(if (number? from-id)
(result-append! (build-connector from-id parent-id from-cell)))
;; recurse
(if (pair? (car xs)) (search (car xs) parent-id "car"))
(if (pair? (cdr xs)) (search (cdr xs) parent-id "cdr"))))))))
(search lst)
(string-append "digraph " graph-name " {\n" result "}\n"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;; Here is where `mystery' begins ;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define t '(1 2 3))
(set-cdr! (cddr t) t)
(define (mystery x)
(define (loop x y graph-num)
(display (list->graphviz x (format #f "graph~a" graph-num)))
(if (null? x)
y
(let ((temp (cdr x)))
(set-cdr! x y)
(loop temp x (+ 1 graph-num)))))
(loop x '() 0))
(mystery t)
The code above code generates Graphviz graph description statements, which must then be processed by dot (Graphviz) to be rendered to a graphical format.
For example, you can run the code above and pipe it into dot:
$ scheme generate_box_ptr.scm | dot -o ptrs.ps -Tps
This command generates a postscript file which has the advantage of separating each list into it's own page if you've run list->graphviz more than once. dot can also output PNGs, PDFs and many other file formats as the manpage describes.
I want to read from stdin element by element but I don't know how to stop when I insert a new line.
Here is my code:
(define readNext
(lambda (tmp)
(let ([a (read)])
(if (equal? a ??????)
tmp
(readNext (cons (read) tmp))))))
I found a solution that works as I expected.
(define a (open-input-string (read-line)))
(define readNext
(lambda (tmp)
(let ([b (read a)])
(if (equal? b eof)
tmp
(readNext (append tmp (list b)))))))
(readNext '())
EDIT: It won't stop on newline but for eof
The function read will read an entire datum.
If you want to read characters until you hit newline,
you will have to one character at a time.
The newline character is written #\newline.
Something like this:
#lang racket
(define read-a-line-as-list
(lambda ()
(let ([c (read-char)])
(if (equal? c #\newline)
'()
(cons c (read-a-line-as-list))))))
(define read-a-line
(lambda ()
(list->string (read-a-line-as-list))))
(read-a-line)
I'm doing it like this
(for ((_ (in-naturals)))
(define l (read-line))
#:break (eof-object? l)
(displayln l))
might not be the most idiomatic, but it works. Use for/list or similar to do something more useful with the lines being read.
I'm having some difficulty understanding how for loops work in scheme. In particular this code runs but I don't know why
(define (bubblesort alist)
;; this is straightforward
(define (swap-pass alist)
(if (eq? (length alist) 1)
alist
(let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
(if (> fst scnd)
(cons scnd (swap-pass (cons fst rest)))
(cons fst (swap-pass (cons scnd rest)))))))
; this is mysterious--what does the 'for' in the next line do?
(let for ((times (length alist))
(val alist))
(if (> times 1)
(for (- times 1) (swap-pass val))
(swap-pass val))))
I can't figure out what the (let for (( is supposed to do here, and the for expression in the second to last line is also a bit off putting--I've had the interpreter complain that for only takes a single argument, but here it appears to take two.
Any thoughts on what's going on here?
That's not a for loop, that's a named let. What it does is create a function called for, then call that; the "looping" behavior is caused by recursion in the function. Calling the function loop is more idiomatic, btw. E.g.
(let loop ((times 10))
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))
gets expanded to something like
(letrec ((loop (lambda (times)
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))))
(loop 10))
This isn't actually using a for language feature but just using a variation of let that allows you to easily write recursive functions. See this documentation on let (it's the second form on there).
What's going on is that this let form binds the name it's passed (in this case for) to a procedure with the given argument list (times and val) and calls it with the initial values. Uses of the bound name in the body are recursive calls.
Bottom line: the for isn't significant here. It's just a name. You could rename it to foo and it would still work. Racket does have actual for loops that you can read about here.
I am trying to make little human like text searching program in scheme
but this program doesn't work properly time to time
and I can't catch the bug for many hours
could somebody tell me what's wrong with my code?
and is it not that good idea for searching text?
when I search the string "exp"
in the text file which contain nothing but just string "explorer"
error arise
and it tells Found 0
(define (search str)
(set! count 0)
(define len (length str))
;null character calculating
(define data-len (- (length data) 1))
;when string length is less than or equal to data-length
(when (and (not (= 0 len)) (>= data-len len))
(define first-char (first str))
(define last-char (last str))
;is it correct?
(define (exact? str len index)
(if (equal? str (drop (take data (+ index len)) index))
#t
#f))
;check first and last character of string if correct, check whether this string is correct completely, if so, skip to next index
(define (loop [index 0])
(when (> data-len index)
(if (and (equal? first-char (list-ref data index))
(equal? last-char (list-ref data (+ index len -1))))
(when (exact? str len index)
(set! count (+ count 1))
(loop (+ index len)))
(loop (+ index 1)))))
(loop))
(send msg set-label (format "Found : ~a" count)))
I know it's been four years, but I'm nostalgic for my SCHEME class, so I made a thing. (I'd comment instead of answering, but I don't have enough reputation yet. ... And I'm probably about to have less.)
(define (find-pattern pat str); Returns a list of locations of PATturn in STRing.
(define (pattern-found? pat-list str-list); Is the pattern (pat-list) at the beginning of this string (str-list)? Also, they're lists, now.
(cond ((null? pat-list) #t); The base case for the recursion.
((null? str-list) #f); Obvious
((eq? (car pat-list) (car str-list)); First letter matches
(pattern-found? (cdr pat-list) (cdr str-list))); Recurse
(else #f)))
(define (look-for-pattern pat-list str-list counter results-list)
(cond ((null? str-list) results-list); Base case
((pattern-found? pat-list str-list)
(look-for-pattern pat-list
(cdr str-list)
(+ counter 1)
(cons counter results-list)))
(else (look-for-pattern pat-list
(cdr str-list)
(+ counter 1)
results-list))))
(look-for-pattern (string->list pat)
(string->list str)
0
'()))
EDIT: I mean it's been four years since the question, not since SCHEME class. That'd be a little creepy, but then again, who knows how I'll feel in three years?
im trying to load a sxml file... i manage to do that in scheme. now i want to go through it using recursion and located items that i want. my code is like this,
(define file (read(open-input-file "test1.sxml")))
(define myfunc
(lambda (S)
(if (eq? "foo" (car S))
(display "found\n")
(display "not found\n")
)
(if (null? (cdr S))
(display "\n")
(myfunc(cdr S)))))
but it seems that it goes through only the first line of the sxml file. how can i make it go through all the file until the end?
1) You need to search through all of the sublists of the structure. Your code right now only looks at the top-most elements.
2) You usually don't want to have multiple statements in a row (like your two if statements)
3) You probably want to look for symbols, not strings, in your SXML file. Regardless, you must use equal? to compare strings.
Thus, your function becomes
(define myfunc
(lambda (S)
(cond
((null? S) #f)
((pair? (car S)) (or (myfunc (car S)) (myfunc (cdr S)))) ; search on sublists
((equal? "foo" (car S)) #t) ; if found, return true
(else (myfunc (cdr S))))))